library("tidyverse")
── Attaching core tidyverse packages ──────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.0     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library("data.table")
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
data.table 1.14.10 using 1 threads (see ?getDTthreads).  Latest news: r-datatable.com
**********
This installation of data.table has not detected OpenMP support. It should still work but in single-threaded mode.
This is a Mac. Please read https://mac.r-project.org/openmp/. Please engage with Apple and ask them for support. Check r-datatable.com for updates, and our Mac instructions here: https://github.com/Rdatatable/data.table/wiki/Installation. After several years of many reports of installation problems on Mac, it's time to gingerly point out that there have been no similar problems on Windows or Linux.
**********

Attaching package: ‘data.table’

The following objects are masked from ‘package:lubridate’:

    hour, isoweek, mday, minute, month, quarter, second, wday, week, yday,
    year

The following objects are masked from ‘package:dplyr’:

    between, first, last

The following object is masked from ‘package:purrr’:

    transpose
library("rtracklayer")
Loading required package: GenomicRanges
Warning: package ‘GenomicRanges’ was built under R version 4.2.2
Loading required package: stats4
Loading required package: BiocGenerics

Attaching package: ‘BiocGenerics’

The following objects are masked from ‘package:lubridate’:

    intersect, setdiff, union

The following objects are masked from ‘package:dplyr’:

    combine, intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    IQR, mad, sd, var, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, aperm, append, as.data.frame, basename, cbind, colnames,
    dirname, do.call, duplicated, eval, evalq, Filter, Find, get, grep, grepl,
    intersect, is.unsorted, lapply, Map, mapply, match, mget, order, paste,
    pmax, pmax.int, pmin, pmin.int, Position, rank, rbind, Reduce, rownames,
    sapply, setdiff, sort, table, tapply, union, unique, unsplit, which.max,
    which.min

Loading required package: S4Vectors
Warning: package ‘S4Vectors’ was built under R version 4.2.2

Attaching package: ‘S4Vectors’

The following objects are masked from ‘package:data.table’:

    first, second

The following objects are masked from ‘package:lubridate’:

    second, second<-

The following objects are masked from ‘package:dplyr’:

    first, rename

The following object is masked from ‘package:tidyr’:

    expand

The following objects are masked from ‘package:base’:

    expand.grid, I, unname

Loading required package: IRanges

Attaching package: ‘IRanges’

The following object is masked from ‘package:data.table’:

    shift

The following object is masked from ‘package:lubridate’:

    %within%

The following objects are masked from ‘package:dplyr’:

    collapse, desc, slice

The following object is masked from ‘package:purrr’:

    reduce

Loading required package: GenomeInfoDb
Warning: package ‘GenomeInfoDb’ was built under R version 4.2.2
library("ggrastr")
library("glue")

Attaching package: ‘glue’

The following object is masked from ‘package:GenomicRanges’:

    trim

The following object is masked from ‘package:IRanges’:

    trim
library("DESeq2")
Loading required package: SummarizedExperiment
Loading required package: MatrixGenerics
Loading required package: matrixStats

Attaching package: ‘matrixStats’

The following object is masked from ‘package:dplyr’:

    count


Attaching package: ‘MatrixGenerics’

The following objects are masked from ‘package:matrixStats’:

    colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse, colCounts,
    colCummaxs, colCummins, colCumprods, colCumsums, colDiffs, colIQRDiffs,
    colIQRs, colLogSumExps, colMadDiffs, colMads, colMaxs, colMeans2,
    colMedians, colMins, colOrderStats, colProds, colQuantiles, colRanges,
    colRanks, colSdDiffs, colSds, colSums2, colTabulates, colVarDiffs,
    colVars, colWeightedMads, colWeightedMeans, colWeightedMedians,
    colWeightedSds, colWeightedVars, rowAlls, rowAnyNAs, rowAnys,
    rowAvgsPerColSet, rowCollapse, rowCounts, rowCummaxs, rowCummins,
    rowCumprods, rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
    rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
    rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks, rowSdDiffs,
    rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars, rowWeightedMads,
    rowWeightedMeans, rowWeightedMedians, rowWeightedSds, rowWeightedVars

Loading required package: Biobase
Welcome to Bioconductor

    Vignettes contain introductory material; view with 'browseVignettes()'. To
    cite Bioconductor, see 'citation("Biobase")', and for packages
    'citation("pkgname")'.


Attaching package: ‘Biobase’

The following object is masked from ‘package:MatrixGenerics’:

    rowMedians

The following objects are masked from ‘package:matrixStats’:

    anyMissing, rowMedians
library("ggpubr")
library("wigglescout")
library("eulerr")
library("ggplot2")
library(corrplot)
corrplot 0.92 loaded
# export 
result_folder = "../results/"
plot_folder = "../results/plots/"
stat_output = "../results/stats/"

combined_bigwigs <- list.files("../mendeley/Figure2","CTCF_ChIP-seq.+bw",
                  full.names = TRUE)
geo_bigwigs <- list.files("../mendeley/Figure2","GSM.+bw",
                  full.names = TRUE)
# colors
mypal <-c("cornflowerblue","orange","red2","darkgreen","#505050")
mypal <-c("#00619D","#A82A34","orange","seagreen","#505050")
mypal2 <-c("#00619D","#7FB0CE","#A82A34","#D39499","orange","#FFD55A","seagreen","#7DBA9C","#505050")
# diff signal function
bw_granges_diff_analysis <- function(granges_c1,
                                     granges_c2,
                                     label_c1,
                                     label_c2,
                                     estimate_size_factors = FALSE,
                                     as_granges = FALSE) {
  # Bind first, get numbers after
  names_values <- NULL
  fields <- names(mcols(granges_c1))
  
  if ("name" %in% fields) {
    names_values <- mcols(granges_c1)[["name"]]
    granges_c1 <- granges_c1[, fields[fields != "name"]]
  }
  
  fields <- names(mcols(granges_c2))
  if ("name" %in% fields) {
    granges_c2 <- granges_c2[, fields[fields != "name"]]
  }
  
  cts_df <- cbind(data.frame(granges_c1), mcols(granges_c2))
  
  if (!is.null(names_values)) {
    rownames(cts_df) <- names_values
  }
  
  # Needs to drop non-complete cases and match rows
  complete <- complete.cases(cts_df)
  cts_df <- cts_df[complete, ]
  
  values_df <- cts_df[, 6:ncol(cts_df)] %>% dplyr::select(where(is.numeric))
  cts <- get_nreads_columns(values_df)
  
  condition_labels <- c(rep(label_c1, length(mcols(granges_c1))), rep(label_c2, length(mcols(granges_c2))))
  
  
  coldata <- data.frame(colnames(cts), condition = as.factor(condition_labels))
  print(coldata)
  
  dds <- DESeq2::DESeqDataSetFromMatrix(
    countData = cts,
    colData = coldata,
    design = ~ condition,
    rowRanges = granges_c1[complete, ]
  )
  
  
  if (estimate_size_factors == TRUE) {
    dds <- DESeq2::estimateSizeFactors(dds)
  }
  else {
    # Since files are scaled, we do not want to estimate size factors
    sizeFactors(dds) <- c(rep(1, ncol(cts)))
  }
  
  dds <- DESeq2::estimateDispersions(dds)
  dds <- DESeq2::nbinomWaldTest(dds)
  
  if (as_granges) {
    result <- DESeq2::results(dds, format = "GRanges", alpha = 0.01)
    if (!is.null(names_values)) {
      result$name <- names_values[complete]
    }
    
  }
  else {
    # result <- results(dds, format="DataFrame")
    result <- dds
  }
  
  result
}

get_nreads_columns <- function(df, length_factor = 100) {
  # Convert mean coverages to round integer read numbers
  cts <- as.matrix(df)
  cts <- as.matrix(cts[complete.cases(cts), ])
  cts <- round(cts * length_factor)
  cts
}
ctcf.and.G4.pro <- import("../peaks/G4 CTCF_with_promoters_sorted.bed")
ctcf.not.G4.pro <- import("../peaks/CTCF-only_with_promoters_sorted.bed")
ctcf.and.G4.npr <- import("../peaks/G4 CTCF_without_promoters_sorted.bed")
ctcf.not.G4.npr <- import("../peaks/CTCF-only_without_promoters_sorted.bed")

ctcf.and.G4.pro$class <- "CTCF_and_G4"
ctcf.not.G4.pro$class <- "CTCF_not_G4"
ctcf.and.G4.npr$class <- "CTCF_and_G4"
ctcf.not.G4.npr$class <- "CTCF_not_G4"
ctcf.and.G4.pro$pro <- "Pro"
ctcf.not.G4.pro$pro <- "Pro"
ctcf.and.G4.npr$pro <- "noPro"
ctcf.not.G4.npr$pro <- "noPro"

ctcf.and.G4 <- c(ctcf.and.G4.pro,ctcf.and.G4.npr)
ctcf.not.G4 <- c(ctcf.not.G4.pro,ctcf.not.G4.npr)
ctcf <- c(ctcf.and.G4,ctcf.not.G4)
ctcf <- sortSeqlevels(ctcf)
ctcf <- sort(ctcf)
names(ctcf) <- paste0(ctcf$class," ",ctcf$pro)
peaks_bed <- "../peaks/CTCF_G4_in_6_categories.bed"
export.bed(ctcf, peaks_bed)

check MACS peak widths

ctcf.raw <- import("../peaks/CTCF_mES_peaks.narrowPeak")
G4.raw <- import("../peaks/G4_WT_peaks.narrowPeak")
ctcf.raw$class <- "CTCF"
G4.raw$class <- "G4"
ctcf.raw$pro <- "NA"
G4.raw$pro <- "NA"
df <- rbind(as.data.frame(ctcf.raw)[c(1,2,3,4,5,12,13)], as.data.frame(G4.raw)[c(1,2,3,4,5,12,13)],as.data.frame(ctcf,row.names = NULL))
ggdensity(df,x="width",y = "density",color = "class", fill="class", alpha=0.1, palette=mypal) + scale_x_continuous(limits = c(100,600))
Warning: Removed 3661 rows containing non-finite outside the scale range (`stat_density()`).

min(width(G4.raw))
[1] 233
min(width(ctcf.raw))
[1] 200
median(width(G4.raw))
[1] 316
median(width(ctcf.raw))
[1] 332

calculate coverage over peaks

# Wulfridge CTCF ChIP-Seq mocks
mocks_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/SRR23958387_GSM7116277_E14_Mock_CTCF_Rep1_Mus_musculus_ChIP-Seq.CPMnorm.bw",
          "../data/CutNTag_ChIP-Seq/bw/SRR23958386_GSM7116278_E14_Mock_CTCF_Rep2_Mus_musculus_ChIP-Seq.CPMnorm.bw")

# PDS
# Wulfridge CTCF ChIP-Seq
pds_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/SRR23958385_GSM7116279_E14_PDS_CTCF_Rep1_Mus_musculus_ChIP-Seq.CPMnorm.bw",
                "../data/CutNTag_ChIP-Seq/bw/SRR23958384_GSM7116280_E14_PDS_CTCF_Rep2_Mus_musculus_ChIP-Seq.CPMnorm.bw")

pdc_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/SRR23958383_GSM7116281_E14_PhenDC3_CTCF_Rep1_Mus_musculus_ChIP-Seq.CPMnorm.bw",
                "../data/CutNTag_ChIP-Seq/bw/SRR23958382_GSM7116282_E14_PhenDC3_CTCF_Rep2_Mus_musculus_ChIP-Seq.CPMnorm.bw")

G4_bigwigs = c("../mendeley/Figure1/G4_CUT-Tag_thisStudy.bw")

cov.mocks <- bw_loci(mocks_bigwigs,peaks_bed,labels=c("mock_1","mock_2"))
cov.pds <- bw_loci(pds_bigwigs,peaks_bed,labels=c("PDS_1","PDS_2"))
cov.pdc <- bw_loci(pdc_bigwigs,peaks_bed,labels=c("PhenDC3_1","PhenDC3_2"))
cov.G4 <- bw_loci(G4_bigwigs,peaks_bed,labels=c("G4_NT"))
cov.combined <- bw_loci(combined_bigwigs,peaks_bed,labels=c("mock","PDS","PhenDC3"))
cov.geo <- bw_loci(geo_bigwigs,peaks_bed,labels=c("GEO_mock","GEO_PDS","GEO_PhenDC3"))

quick comparison on deposited and reprocessed bigwig files

corr_df <- data.frame(data.frame(cov.combined)[,c(9,6,7,8)],data.frame(cov.geo)[,6:8],data.frame(cov.mocks)[,6:7],data.frame(cov.pds)[,6:7],data.frame(cov.pdc)[,6:7])
res <- cor(corr_df[,2:13])
corrplot(res, type = "upper", order = "hclust",tl.col = "black", tl.srt = 45,addCoef.col = 'black',tl.pos = 'd',    cl.pos = 'n', col.lim=c(0.93, 1),is.corr = F, method = 'color')

p1 <- plot_bw_profile(c(mocks_bigwigs[1],pds_bigwigs[1],pdc_bigwigs[1]),loci = "../peaks/G4 CTCF_with_promoters_sorted.bed",mode = "center",verbose = F) + coord_cartesian(ylim=c(0,2.4))
p2 <- plot_bw_profile(c(mocks_bigwigs[2],pds_bigwigs[2],pdc_bigwigs[2]),loci = "../peaks/G4 CTCF_with_promoters_sorted.bed",mode = "center",verbose = F) + coord_cartesian(ylim=c(0,2.4))
p3 <- plot_bw_profile(bwfiles = combined_bigwigs,loci = "../peaks/G4 CTCF_with_promoters_sorted.bed",mode = "center",verbose = F) + coord_cartesian(ylim=c(0,2.4))
ggarrange(p1,p2,p3, ncol=3)

p1 <- plot_bw_profile(bwfiles = geo_bigwigs,loci = "../peaks/G4 CTCF_with_promoters_sorted.bed",mode = "center",verbose = F) + coord_cartesian(ylim=c(0,5))
p2 <- plot_bw_profile(bwfiles = combined_bigwigs,loci = "../peaks/G4 CTCF_with_promoters_sorted.bed",mode = "center",verbose = F) + coord_cartesian(ylim=c(0,2.6))
ggarrange(p1,p2, ncol=2)

p1 <- plot_bw_profile(bwfiles = geo_bigwigs,loci = "../peaks/CTCF-only_with_promoters_sorted.bed",mode = "center",verbose = F) + coord_cartesian(ylim=c(0,5))
Warning in .summarize_matrix(fg, label) :
  Profile plot: 324 generated ( 0.0538563829787234 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 324 generated ( 0.0538563829787234 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 324 generated ( 0.0538563829787234 per locus)
p2 <- plot_bw_profile(bwfiles = combined_bigwigs,loci = "../peaks/CTCF-only_with_promoters_sorted.bed",mode = "center",verbose = F) + coord_cartesian(ylim=c(0,2.6))
Warning in .summarize_matrix(fg, label) :
  Profile plot: 324 generated ( 0.0538563829787234 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 324 generated ( 0.0538563829787234 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 324 generated ( 0.0538563829787234 per locus)
ggarrange(p1,p2, ncol=2)

p1 <- plot_bw_loci_scatter(mocks_bigwigs[1],mocks_bigwigs[2], loci = "../peaks/G4 CTCF_with_promoters_sorted.bed", verbose = F)
p2 <- plot_bw_loci_scatter(pds_bigwigs[1],pds_bigwigs[2], loci = "../peaks/G4 CTCF_with_promoters_sorted.bed", verbose = F)
p3 <- plot_bw_loci_scatter(pdc_bigwigs[1],pdc_bigwigs[2], loci = "../peaks/G4 CTCF_with_promoters_sorted.bed", verbose = F)
ggarrange(p1,p2,p3, ncol=3)

p1 <- plot_bw_loci_scatter(combined_bigwigs[1],combined_bigwigs[2], loci = "../peaks/G4 CTCF_with_promoters_sorted.bed", verbose = F)
p2 <- plot_bw_loci_scatter(combined_bigwigs[2],combined_bigwigs[3], loci = "../peaks/G4 CTCF_with_promoters_sorted.bed", verbose = F)
p3 <- plot_bw_loci_scatter(combined_bigwigs[1],combined_bigwigs[3], loci = "../peaks/G4 CTCF_with_promoters_sorted.bed", verbose = F)
ggarrange(p1,p2,p3, ncol=3)

results <- data.frame(
  as.data.frame(cov.mocks),
  as.data.frame(cov.pds)[6:7],
  as.data.frame(cov.pdc)[6:7],
  as.data.frame(cov.G4)[6],
  raw.lfc.pds_1 = log2(cov.pds$PDS_1 / cov.mocks$mock_1),
  raw.lfc.pds_2 = log2(cov.pds$PDS_2 / cov.mocks$mock_2),
  raw.lfc.pdc_1 = log2(cov.pds$PDS_1 / cov.mocks$mock_1),
  raw.lfc.pdc_2 = log2(cov.pdc$PhenDC3_2 / cov.mocks$mock_2),
  raw.lfc.pds = log2(rowMeans(as.data.frame(cov.pds)[6:7]) / rowMeans(as.data.frame(cov.mocks)[6:7])),
  raw.lfc.pdc = log2(rowMeans(as.data.frame(cov.pdc)[6:7]) / rowMeans(as.data.frame(cov.mocks)[6:7])),
  mean.mock = rowMeans(as.data.frame(cov.mocks)[6:7]),
  mean.pds = rowMeans(as.data.frame(cov.pds)[6:7]),
  mean.pdc = rowMeans(as.data.frame(cov.pdc)[6:7])
)

cov.mocks$name <- NULL
cov.pds$name <- NULL
cov.pdc$name <- NULL

de_pds <- bw_granges_diff_analysis(cov.mocks, cov.pds, "Mock", "PDS")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
lfc_pds = DESeq2::lfcShrink(de_pds, coef = "condition_PDS_vs_Mock", type = "apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
de_pdc <- bw_granges_diff_analysis(cov.mocks, cov.pdc, "Mock", "PhenDC3")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
lfc_pdc = DESeq2::lfcShrink(de_pdc, coef = "condition_PhenDC3_vs_Mock", type = "apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
results$deseq.lfc.pds <- results(de_pds)$log2FoldChange
results$deseq.lfcs.pds <- lfc_pds$log2FoldChange
results$deseq.padj.pds <- lfc_pds$padj
results$deseq.mean.pds <- log2(lfc_pds$baseMean)
results$deseq.sig.pds <- lfc_pds$pvalue < 0.05

results$deseq.lfc.pdc <- results(de_pdc)$log2FoldChange
results$deseq.lfcs.pdc <- lfc_pdc$log2FoldChange
results$deseq.padj.pdc <- lfc_pdc$padj
results$deseq.mean.pdc <- log2(lfc_pdc$baseMean)
results$deseq.sig.pdc <- lfc_pdc$pvalue < 0.05

results$class <- gsub(" .+", "", results$name)
results$pro <- gsub(".+ ", "", results$name)
results$pro <- factor(results$pro, levels = c("Pro", "noPro"))
results$class <- factor(results$class, levels = c("CTCF_and_G4", "CTCF_not_G4"))

results$log2.mock <- log2(results$mean.mock)
results$log2.pds <- log2(results$mean.pds)
results$log2.pdc <- log2(results$mean.pdc)
results$log2.G4 <- log2(results$G4_NT)

results$deseq.sigup.pds <- results$deseq.sig.pds &
  results$deseq.lfc.pds > 0
results$deseq.sigup.pdc <- results$deseq.sig.pdc &
  results$deseq.lfc.pdc > 0
write.table(results, glue("{result_folder}foldchange_results.txt"))
table(results$name)

CTCF_and_G4 noPro   CTCF_and_G4 Pro CTCF_not_G4 noPro   CTCF_not_G4 Pro 
              988              1300             43309              6016 
#results <- read.table("foldchange_results.txt")
results$class <- factor(results$class, levels = c("CTCF_and_G4", "CTCF_not_G4"))
p <- ggviolin(
  results,
  x = "class",
  y = "mean.mock",
  fill = "class",
  palette = mypal,
  add = "median_iqr"
) + coord_cartesian(ylim = c(0, 10))
annotate_figure(p, fig.lab = "CTCF signal by class in mock condition, mean of two reps, median+iqr", fig.lab.size = 6)

ggsave(glue("{plot_folder}Violin_CTCF_classes.pdf"), last_plot())
Saving 3 x 3 in image
p <- ggviolin(
  results,
  x = "class",
  y = "mean.mock",
  fill = "pro",
  palette = mypal,
  add = "median_iqr"
) + coord_cartesian(ylim = c(0, 10))
annotate_figure(p, fig.lab = "CTCF signal by class in mock condition, mean of two reps, median+iqr", fig.lab.size = 6)

ggsave(glue("{plot_folder}Violin_CTCF_classes_pro.pdf"),
       last_plot())
Saving 3 x 3 in image
mdf <- reshape2::melt(dplyr::select(
  results,
  c(
    "class",
    "mock_1",
    "mock_2",
    "PDS_1",
    "PDS_2",
    "PhenDC3_1",
    "PhenDC3_2"
  )
))
Using class as id variables
ggboxplot(
  mdf,
  x = "variable",
  y = "value",
  fill = "class",
  palette = mypal
) + coord_cartesian(ylim = c(0, 10))

ggsave(glue("{plot_folder}Boxplot_CTCF_reps.pdf"), last_plot())
Saving 5 x 3 in image
mdf <- reshape2::melt(dplyr::select(
  results,
  c(
    "class",
    "mock_1",
    "mock_2",
    "PDS_1",
    "PDS_2",
    "PhenDC3_1",
    "PhenDC3_2"
  )
))
Using class as id variables
mdf_stats_class = compare_means(value ~ class, group.by = "variable", data = mdf)

ggviolin(
  mdf,
  x = "variable",
  y = "value",
  fill = "class",
  palette = mypal,
  add = "median_iqr"
) + coord_cartesian(ylim = c(0, 10))

ggsave(glue("{plot_folder}Violin_CTCF_reps.pdf"), last_plot())
Saving 5 x 3 in image
mdf <- reshape2::melt(dplyr::select(results, c(
  "class", "deseq.lfc.pds", "deseq.lfc.pdc"
)))
Using class as id variables
p <- ggviolin(
  mdf,
  x = "variable",
  y = "value",
  fill = "class",
  palette = mypal,
  add = "median_iqr"
) + geom_hline(yintercept = 0, linetype = "dotted") + coord_cartesian(ylim =
                                                                        c(-3, 3)) + stat_compare_means(aes(group = class), label.y = 3, size = 2)

annotate_figure(p, fig.lab = "DESEq foldchange mean treat vs mean mock, median+iqr", fig.lab.size = 6)
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_compare_means()`).

ggsave(
  glue("{plot_folder}Violin_CTCF_lfc.pdf"),
  last_plot(),
  width = 5,
  height = 5
)
p <- ggboxplot(
  mdf,
  x = "variable",
  y = "value",
  fill = "class",
  palette = mypal
) + geom_hline(yintercept = 0, linetype = "dotted") + coord_cartesian(ylim =
                                                                        c(-2, 2))
annotate_figure(p, fig.lab = "DESEq foldchange mean treat vs mean mock, median+iqr", fig.lab.size = 6)
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_boxplot()`).

ggsave(glue("{plot_folder}Boxplot_CTCF_lfc.pdf"), last_plot())
Saving 3 x 3 in image
mdf <- reshape2::melt(dplyr::select(results, c(
  "pro", "class", "deseq.lfc.pds", "deseq.lfc.pdc"
)))
Using pro, class as id variables
mdf$pro <- factor(mdf$pro, levels = c("Pro", "noPro"))
mdf$x <- as.factor(paste0(mdf$class, " ", mdf$variable))
mdf$x <- factor(mdf$x, levels = levels(mdf$x)[c(2, 1, 4, 3)])
p <- ggviolin(
  mdf,
  x = "x",
  y = "value",
  fill = "class",
  palette = mypal,
  add = "median_iqr",
  facet.by = "pro"
) + geom_hline(yintercept = 0, linetype = "dotted") + coord_cartesian(ylim =
                                                                        c(-2, 2)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))
annotate_figure(p, fig.lab = "DESEq foldchange mean treat vs mean mock, median+iqr", fig.lab.size = 6)
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).

ggsave(glue("{plot_folder}Violin_CTCF_lfc_pro.pdf"), last_plot())
Saving 5 x 6 in image
med <- aggregate(deseq.lfc.pds ~ class,
                 data = results,
                 FUN = "median",
                 na.rm = T)
med$deseq.fc.pds <- 2 ^ med$deseq.lfc.pds
med
med <- aggregate(deseq.lfc.pds ~ name,
                 data = results,
                 FUN = "median",
                 na.rm = T)
med$deseq.fc.pds <- 2 ^ med$deseq.lfc.pds
med
med <- aggregate(deseq.lfc.pds ~ class,
                 data = results,
                 FUN = "median",
                 na.rm = T)
med$deseq.fc.pds <- 2 ^ med$deseq.lfc.pds
med
med <- aggregate(deseq.lfc.pdc ~ name,
                 data = results,
                 FUN = "median",
                 na.rm = T)
med$deseq.fc.pdc <- 2 ^ med$deseq.lfc.pdc
med
deseq_lfc_stats = compare_means(deseq.lfc.pds ~ class, data = results)
deseq_lfc_stats
write_tsv(deseq_lfc_stats,
          glue("{stat_output}pds-deseq2_lfc_statistics.tsv"))
deseq_lfc_stats = compare_means(deseq.lfc.pdc ~ class, data = results)
deseq_lfc_stats
write_tsv(deseq_lfc_stats,
          glue("{stat_output}phendc-deseq2_lfc_statistics.tsv"))
mdf <- reshape2::melt(dplyr::select(
  results,
  c(
    "class",
    "raw.lfc.pds_1",
    "raw.lfc.pds_2",
    "raw.lfc.pdc_1",
    "raw.lfc.pdc_2"
  )
))
Using class as id variables
ggviolin(
  mdf,
  x = "variable",
  y = "value",
  fill = "class",
  palette = mypal,
  add = "median_iqr"
) + geom_hline(yintercept = 0, linetype = "dotted") + coord_cartesian(ylim =
                                                                        c(-3, 3)) +
  stat_compare_means(aes(group = class), label.y = 3.6, size = 2)
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_summary()`).
Warning: Removed 469 rows containing non-finite outside the scale range
(`stat_compare_means()`).

ggsave(glue("{plot_folder}Violin_CTCF_lfc_individual_reps.pdf"), last_plot())
Saving 5 x 3 in image
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_summary()`).
Warning: Removed 469 rows containing non-finite outside the scale range
(`stat_compare_means()`).
ggdensity(
  results,
  x = "raw.lfc.pds",
  color = "class",
  fill = "class",
  palette = mypal
) + geom_vline(xintercept = 0, linetype = "dotted")
Warning: Removed 26 rows containing non-finite outside the scale range (`stat_density()`).

ggdensity(
  results,
  x = "raw.lfc.pdc",
  color = "class",
  fill = "class",
  palette = mypal
) + geom_vline(xintercept = 0, linetype = "dotted")
Warning: Removed 23 rows containing non-finite outside the scale range (`stat_density()`).

ggscatter(
  results,
  x = "log2.mock",
  y = "log2.pds",
  size = 1,shape=20,
  alpha = 0.1,
  color = "deseq.sig.pds",
  palette = mypal[c(5, 2)]
)

ggsave(glue("{plot_folder}Scatter_CTCF_DESEq_PDSvsMock.pdf"), rasterize(last_plot(),dpi = 600),width = 3, height= 3.2)
ggscatter(
  results,
  x = "log2.mock",
  y = "log2.pdc",
  size = 1,shape=20,
  alpha = 0.1,
  color = "deseq.sig.pdc",
  palette = mypal[c(5, 2)]
)

ggsave(glue("{plot_folder}Scatter_CTCF_DESEq_PhenDC3vsMock.pdf"), rasterize(last_plot(),dpi = 600),width = 3, height= 3.2)
tb <- table(results$class)
deseq.stats <- as.data.frame(t(as.matrix(tb)))
deseq.stats[1,] <- colSums(deseq.stats)
rownames(deseq.stats) <- c("Total")
deseq.stats.percent <- deseq.stats
deseq.stats.percent[1,] <- c(100,100)
tb

CTCF_and_G4 CTCF_not_G4 
       2288       49325 
tb <- table(results$deseq.sig.pds &
        (results$deseq.lfc.pds > 0),
      results$class)
deseq.stats <- rbind(deseq.stats, PDS.sig.up = as.data.frame.matrix(tb)[2,])
tb
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2220       46812
  TRUE           68        2510
tb <- prop.table(table(results$deseq.sig.pds &
        (results$deseq.lfc.pds > 0),
      results$class),margin = 2)*100
deseq.stats.percent <- rbind(deseq.stats.percent, PDS.sig.up  = as.data.frame.matrix(tb)[2,])
tb
       
        CTCF_and_G4 CTCF_not_G4
  FALSE   97.027972   94.910993
  TRUE     2.972028    5.089007
table(results$deseq.sig.pds &
        (results$deseq.lfc.pds > 0),
      results$class)
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2220       46812
  TRUE           68        2510
mdf <- reshape2::melt(table(
  results$deseq.sig.pds & (results$deseq.lfc.pds > 0),
  results$class
))
ggplot(mdf, aes(Var1, Var2, fill = value)) +
  geom_tile(show.legend = F) + geom_text(aes(label = value)) +
  scale_fill_gradient(low = "white", high = "orange") + theme_minimal()

vl <- list(
  sig = grep("TRUE", results$deseq.sigup.pds),
  CTCF_G4 = grep("and", results$class),
  CTCFonly = grep("not", results$class)
)
plot(euler(vl), quantities = T)

tb <- table(results$deseq.sig.pdc &
        (results$deseq.lfc.pdc > 0),
      results$class)
deseq.stats <- rbind(deseq.stats, PhenDC3.sig.up = as.data.frame.matrix(tb)[2,])
tb
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2251       48545
  TRUE           37         780
tb <- prop.table(table(results$deseq.sig.pdc &
        (results$deseq.lfc.pdc > 0),
      results$class),margin = 2)*100
deseq.stats.percent <- rbind(deseq.stats.percent, PhenDC3.sig.up = as.data.frame.matrix(tb)[2,])
tb
       
        CTCF_and_G4 CTCF_not_G4
  FALSE   98.382867   98.418652
  TRUE     1.617133    1.581348
table(results$deseq.sig.pdc &
        (results$deseq.lfc.pdc > 0),
      results$class)
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2251       48545
  TRUE           37         780
mdf <- reshape2::melt(table(
  results$deseq.sig.pdc & (results$deseq.lfc.pdc > 0),
  results$class
))
ggplot(mdf, aes(Var1, Var2, fill = value)) +
  geom_tile(show.legend = F) + geom_text(aes(label = value)) +
  scale_fill_gradient(low = "white", high = "orange") + theme_minimal()

results$uid <- seq(1:nrow(results))
vl <- list(
  sig = grep("TRUE", results$deseq.sigup.pdc),
  CTCF_G4 = grep("and", results$class),
  CTCFonly = grep("not", results$class)
)
plot(euler(vl), quantities = T)

table(results$deseq.sigup.pds, results$deseq.sigup.pdc)
       
        FALSE  TRUE
  FALSE 48576   456
  TRUE   2217   361
mdf <- reshape2::melt(table(results$deseq.sigup.pds, results$deseq.sigup.pdc))
ggplot(mdf, aes(Var1, Var2, fill = value)) +
  geom_tile(show.legend = F) + geom_text(aes(label = value)) +
  scale_fill_gradient(low = "white", high = "orange") + theme_minimal()

tb <- table(results$deseq.sigup.pds & results$deseq.sigup.pdc,
      results$class)
deseq.stats <- rbind(deseq.stats, both.sig.up = as.data.frame.matrix(tb)[2,])
tb
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2277       48975
  TRUE           11         350
tb <- prop.table(table(results$deseq.sigup.pds & results$deseq.sigup.pdc,
      results$class),margin = 2)*100
deseq.stats.percent <- rbind(deseq.stats.percent, both = as.data.frame.matrix(tb)[2,])
tb
       
        CTCF_and_G4 CTCF_not_G4
  FALSE  99.5192308  99.2904207
  TRUE    0.4807692   0.7095793
table(results$deseq.sigup.pds & results$deseq.sigup.pdc, results$class)
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2277       48975
  TRUE           11         350
mdf <- reshape2::melt(table(results$deseq.sigup.pds & results$deseq.sigup.pdc, results$class))
ggplot(mdf, aes(Var1, Var2, fill = value)) +
  geom_tile(show.legend = F) + geom_text(aes(label = value)) +
  scale_fill_gradient(low = "white", high = "orange") + theme_minimal()

deseq.stats$class <- rownames(deseq.stats) 
mdf <- reshape2::melt(deseq.stats)
Using class as id variables
ggplot(mdf, aes(variable, class, fill = value)) +
  geom_tile(show.legend = F) + geom_text(aes(label = value)) +
  scale_fill_gradient(low = "white", high = "orange") + theme_minimal()

ggsave(glue("{plot_folder}Table_CTCF_DESEq_Sigup.pdf"), rasterize(last_plot(),dpi = 600),width = 2.5, height= 2.5)
deseq.stats.percent$class <- rownames(deseq.stats.percent) 
mdf <- reshape2::melt(deseq.stats.percent[-1,])
Using class as id variables
ggplot(mdf, aes(variable, class, fill = value)) +
  geom_tile(show.legend = F) + geom_text(aes(label = round(mdf$value,2))) +
  scale_fill_gradient(low = "white", high = "orange") + theme_minimal()
Warning: Use of `mdf$value` is discouraged.
ℹ Use `value` instead.

ggsave(glue("{plot_folder}Table_CTCF_DESEq_Sigup_percent.pdf"), rasterize(last_plot(),dpi = 600),width = 2.5, height= 2.5)
Warning: Use of `mdf$value` is discouraged.
ℹ Use `value` instead.
vl <- list(
  sig_PDS = grep("TRUE", results$deseq.sigup.pds),
  sig_PDC = grep("TRUE", results$deseq.sigup.pdc),
  CTCF_G4 = grep("and", results$class),
  CTCFonly = grep("not", results$class)
)
plot(euler(vl), quantities = T)

results$uid <- seq(1:nrow(results))
vl <- list(
  sig_PDS = grep("TRUE", results$deseq.sigup.pds),
  sig_PDC = grep("TRUE", results$deseq.sigup.pdc),
  CTCF_G4 = grep("and", results$class)
)
plot(euler(vl), quantities = T)

results$sig.by.class.pds <- paste0(results$deseq.sigup.pds, "_", results$class)
results$psize <- 0.01
results$psize[results$deseq.sigup.pds &
                results$class == "CTCF_and_G4"] <- 1

ggscatter(
  results,
  x = "log2.mock",
  y = "log2.pds",
  size = 0.5,
  alpha = results$psize,
  color = "sig.by.class.pds",
  palette = c(mypal[5], mypal[5], mypal[5], mypal[2], mypal[1])
)

ggscatter(
  results[!grepl("NA", results$sig.by.class.pds), ],
  x = "log2.mock",
  y = "deseq.lfc.pds",
  size = 0.2,
  alpha = "psize",
  color = "sig.by.class.pds",
  palette = c("#505050", "#505050", "red2", "blue")
)

ggscatterhist(
  results[!grepl("NA", results$sig.by.class.pds), ],
  x = "log2.mock",
  y = "log2.pds",
  size = 0.4,
  alpha = "psize",
  color = "sig.by.class.pds",
  margin.params = list(
    fill = "sig.by.class.pds",
    color = "black",
    size = 0.2
  ),
  palette = c("#505050", "#505050", "red2", "blue")
)
Warning: Removed 13 rows containing non-finite outside the scale range (`stat_density()`).
Warning: Removed 10 rows containing non-finite outside the scale range (`stat_density()`).

ggscatter(
  results,
  x = "raw.lfc.pds",
  y = "log2.G4",
  size = 0.2,
  alpha = 0.1,
  color = "deseq.sig.pds",
  cor.coef = T,
  palette = c("#888888",mypal[2])
)
Warning: Removed 16803 rows containing non-finite outside the scale range (`stat_cor()`).
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_point()`).

ggsave(glue("{plot_folder}Scatter_G4_vs_LFC_PDS.pdf"),
       plot = rasterize(last_plot()))
Saving 3 x 3 in image
Warning: Removed 16803 rows containing non-finite outside the scale range (`stat_cor()`).
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_point()`).
ggscatter(
  results,
  x = "raw.lfc.pdc",
  y = "log2.G4",
  size = 0.2,
  alpha = 0.1,
  color = "deseq.sig.pdc",
  cor.coef = T,
  palette = c("#888888",mypal[2])
)
Warning: Removed 16800 rows containing non-finite outside the scale range (`stat_cor()`).

ggsave(glue("{plot_folder}Scatter_G4_vs_LFC_PDC.pdf"),
       plot = rasterize(last_plot()))
Saving 3 x 3 in image
Warning: Removed 16800 rows containing non-finite outside the scale range (`stat_cor()`).
results$G4.quantile <- dplyr::ntile(results$G4_NT, n = 5)
results$pds.quantile <- dplyr::ntile(results$mean.pds-results$mean.mock, n = 4)
results$pdc.quantile <- dplyr::ntile(results$mean.pdc-results$mean.mock, n = 4)
tb <- table(results$pds.quantile, results$class)
tb
   
    CTCF_and_G4 CTCF_not_G4
  1         540       12364
  2         639       12264
  3         552       12351
  4         557       12346
ggbarplot(as.data.frame(t(as.matrix(tb))),"Var2","Freq",fill="Var1",palette = c(mypal[1],"#aaaaaa"),label = TRUE, lab.pos="in",ylim=c(11000,13000))

ggsave(glue("{plot_folder}Barplot_peakCat_by_PDSquantile.pdf"),
       plot = last_plot())
Saving 4 x 3 in image
ggviolin(
  results,
  x = "pds.quantile",
  y = "deseq.lfc.pds",
  fill = mypal[3],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-1.5, 1.5)) + geom_hline(yintercept = 0, linetype =
                                                    "dotted")
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).

ggsave(glue("{plot_folder}Violin_lfcPDS_by_PDSquantile.pdf"),
       plot = last_plot())
Saving 3 x 3 in image
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).
top25.pds <- makeGRangesFromDataFrame(results[results$pds.quantile==4,1:3],na.rm=T)
bot75.pds <- makeGRangesFromDataFrame(results[results$pds.quantile!=4,1:3],na.rm=T)
p1 <- plot_bw_profile(bwfiles = geo_bigwigs,loci = top25.pds, mode = "center",verbose = F, colors = mypal) + coord_cartesian(ylim=c(0,6))
Warning in .summarize_matrix(fg, label) :
  Profile plot: 658 generated ( 0.0509958924281175 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 658 generated ( 0.0509958924281175 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 658 generated ( 0.0509958924281175 per locus)
p2 <- plot_bw_profile(bwfiles = geo_bigwigs,loci = bot75.pds, mode = "center",verbose = F, colors = mypal) + coord_cartesian(ylim=c(0,6))
Warning in .summarize_matrix(fg, label) :
  Profile plot: 2056 generated ( 0.0531128907259106 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 2056 generated ( 0.0531128907259106 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 2056 generated ( 0.0531128907259106 per locus)
ggarrange(p1,p2, ncol=2)

ggsave(glue("{plot_folder}Profile_CTCF_top25_PDSquantile.pdf"),
       plot = last_plot())
Saving 6 x 3 in image
top25.pds.CTCF_G4 <- makeGRangesFromDataFrame(results[(results$pds.quantile==4 & results$class == "CTCF_and_G4"),1:3],na.rm=T)
top25.pds.CTCF_only <- makeGRangesFromDataFrame(results[(results$pds.quantile==4  &  results$class == "CTCF_not_G4"),1:3],na.rm=T)

p1 <- plot_bw_profile(bwfiles = geo_bigwigs[1:2],loci = top25.pds.CTCF_G4, mode = "center",verbose = F, colors = mypal[c(1,2)]) + coord_cartesian(ylim=c(0,10))
p2 <- plot_bw_profile(bwfiles = geo_bigwigs[1:2],loci = top25.pds.CTCF_only, mode = "center",verbose = F, colors = mypal[c(1,2)]) + coord_cartesian(ylim=c(0,10))
Warning in .summarize_matrix(fg, label) :
  Profile plot: 639 generated ( 0.0517576543009882 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 639 generated ( 0.0517576543009882 per locus)
ggarrange(p1,p2, ncol=2)

ggsave(glue("{plot_folder}Profile_CTCF_top25_PDSquantile_byG4overlap.pdf"),
       plot = last_plot())
Saving 6 x 3 in image
top25.pds.CTCF_G4 <- makeGRangesFromDataFrame(results[(results$pds.quantile==4 & results$class == "CTCF_and_G4"),1:3],na.rm=T)
top25.pds.CTCF_only <- makeGRangesFromDataFrame(results[(results$pds.quantile==4  &  results$class == "CTCF_not_G4"),1:3],na.rm=T)

p1 <- plot_bw_profile(bwfiles = geo_bigwigs[2],bg_bwfiles = geo_bigwigs[1], loci = top25.pds.CTCF_G4, mode = "center",verbose = F, colors = mypal[2],norm_mode = "log2fc",show_error = T) + coord_cartesian(ylim=c(-1,1))
Warning in plot_bw_profile(bwfiles = geo_bigwigs[2], bg_bwfiles = geo_bigwigs[1],  :
  Stderr estimate not available when normalizing by input
p2 <- plot_bw_profile(bwfiles = geo_bigwigs[2],bg_bwfiles = geo_bigwigs[1], loci = top25.pds.CTCF_only, mode = "center",verbose = F, colors = mypal[2],norm_mode = "log2fc",show_error = T) + coord_cartesian(ylim=c(-1,1))
Warning in .summarize_matrix(fg, label) :
  Profile plot: 639 generated ( 0.0517576543009882 per locus)
Warning in .summarize_matrix(bg, "bg") :
  Profile plot: 639 generated ( 0.0517576543009882 per locus)
Warning in plot_bw_profile(bwfiles = geo_bigwigs[2], bg_bwfiles = geo_bigwigs[1],  :
  Stderr estimate not available when normalizing by input
ggarrange(p1,p2, ncol=2)

ggsave(glue("{plot_folder}Profile_CTCFfoldchange_top25_PDSquantile_byG4.pdf"),
       plot = last_plot())
Saving 6 x 3 in image
top25.pds.CTCF_G4 <- makeGRangesFromDataFrame(results[(results$pds.quantile==4 & results$class == "CTCF_and_G4"),1:3],na.rm=T)
top25.pds.CTCF_only <- makeGRangesFromDataFrame(results[(results$pds.quantile==4  &  results$class == "CTCF_not_G4"),1:3],na.rm=T)

p1 <- plot_bw_profile(bwfiles = G4_bigwigs, loci = top25.pds.CTCF_G4, mode = "center",verbose = F, colors = mypal[3],norm_mode = "log2fc") + coord_cartesian(ylim=c(0,10))
p2 <- plot_bw_profile(bwfiles = G4_bigwigs, loci = top25.pds.CTCF_only, mode = "center",verbose = F, colors = mypal[3],norm_mode = "log2fc") + coord_cartesian(ylim=c(0,10))
ggarrange(p1,p2, ncol=2)

ggsave(glue("{plot_folder}Profile_G4_top25_PDSquantile.pdf"),
       plot = last_plot())
Saving 6 x 3 in image
ord.top25 <- order(rowMeans(as.data.frame(bw_heatmap(bwfiles = geo_bigwigs[1],loci = top25.pds, mode = "center"))))
p1 <- plot_bw_heatmap(bwfiles = geo_bigwigs[1],loci = top25.pds, mode = "center",verbose = F, zmax = 10, max_rows_allowed = 50, order_by = ord.top25)
Warning in .preprocess_heatmap_matrix(values[[1]], zmin, zmax, order_by,  :
  Large matrix: 12903. Downscaled to 50
p2 <- plot_bw_heatmap(bwfiles = geo_bigwigs[2],loci = top25.pds, mode = "center",verbose = F, zmax = 10, max_rows_allowed = 50, order_by = ord.top25)
Warning in .preprocess_heatmap_matrix(values[[1]], zmin, zmax, order_by,  :
  Large matrix: 12903. Downscaled to 50
ggarrange(p1,p2, ncol=2, common.legend = T)

ggsave(glue("{plot_folder}Heatmap_CTCF_top25_PDSquantile.pdf"),
       plot = last_plot())
Saving 3 x 3 in image
ord.bot75 <- order(rowMeans(as.data.frame(bw_heatmap(bwfiles = geo_bigwigs[1],loci = bot75.pds, mode = "center"))))
p1 <- plot_bw_heatmap(bwfiles = geo_bigwigs[1],loci = bot75.pds, mode = "center",verbose = F, zmax = 10, max_rows_allowed = 200, order_by = ord.bot75)
Warning in .preprocess_heatmap_matrix(values[[1]], zmin, zmax, order_by,  :
  Large matrix: 38710. Downscaled to 200
p2 <- plot_bw_heatmap(bwfiles = geo_bigwigs[2],loci = bot75.pds, mode = "center",verbose = F, zmax = 10, max_rows_allowed = 200, order_by = ord.bot75)
Warning in .preprocess_heatmap_matrix(values[[1]], zmin, zmax, order_by,  :
  Large matrix: 38710. Downscaled to 200
ggarrange(p1,p2, ncol=2, common.legend = T)

ggsave(glue("{plot_folder}Heatmap_CTCF_bot75_PDSquantile.pdf"),
       plot = last_plot())
Saving 3 x 4 in image
G4_CnR <- bw_loci(c("../mendeley/FigureS2/GSM6634325_E14_Mock_G4.bw","../mendeley/FigureS2/GSM6634326_E14_PDS_G4.bw"),loci = makeGRangesFromDataFrame(results,na.rm=T),labels = c("Mock","PDS"))
results$G4_CnR_delta <- G4_CnR$PDS-G4_CnR$Mock
results$G4_CnR_lfc <- log2(G4_CnR$PDS/G4_CnR$Mock)
results$G4_CnR_mock <- G4_CnR$Mock
ggviolin(
  results,
  x = "pds.quantile",
  y = "G4_CnR_delta",
  fill = mypal[2],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-10, 15)) + geom_hline(yintercept = 0, linetype =
                                                    "dotted")

ggsave(glue("{plot_folder}Violin_G4_CnR_delta_by_PDSquantile.pdf"),
       plot = last_plot())
Saving 3 x 2 in image
compare_means(G4_CnR_delta ~ pds.quantile, results)
results$pds.quartile.top25 <- results$pds.quantile == 4
mean(na.omit(results$G4_CnR_delta))
[1] 2.193939
mean(results$G4_CnR_delta[results$pds.quartile.top25])
[1] 2.32057
mean(results$G4_CnR_delta[!results$pds.quartile.top25])
[1] 2.151729
compare_means(G4_CnR_delta ~ pds.quartile.top25, results)
export.bed(top25.pds,"../peaks/CTCF_peaks_top25_pds_up.bed")
export.bed(bot75.pds,"../peaks/CTCF_peaks_bot75_pds_up.bed")
ggviolin(
  results,
  x = "G4.quantile",
  y = "deseq.lfc.pds",
  fill = mypal[1],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-2, 2)) + geom_hline(yintercept = 0, linetype =
                                                    "dotted")
ggsave(glue("{plot_folder}Violin_CTCF_lfc_by_G4quantile.pdf"),
       plot = last_plot())
ggviolin(
  results,
  x = "G4.quantile",
  y = "log2.G4",
  fill = mypal2[5],
  add = "median_iqr"
) + geom_hline(yintercept = 0, linetype = "dotted")
ggsave(glue("{plot_folder}Violin_G4_by_G4quantile.pdf"), plot = last_plot())
peak_cats <- bedscout::import_named_bed_into_list(peaks_bed)
plot_bw_profile(
  G4_bigwigs,
  peak_cats,
  labels = c(
    peak_cats[[1]][1, ]$name,
    peak_cats[[2]][1, ]$name,
    peak_cats[[3]][1, ]$name,
    peak_cats[[4]][1, ]$name
  ),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal
)
plot_bw_profile(
  combined_bigwigs[1],
  peak_cats,
  labels = c(
    peak_cats[[1]][1, ]$name,
    peak_cats[[2]][1, ]$name,
    peak_cats[[3]][1, ]$name,
    peak_cats[[4]][1, ]$name
  ),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal
)
p1 <- plot_bw_profile(
  c(mocks_bigwigs, pds_bigwigs),
  peak_cats[[1]],
  labels = c("mock1", "mock2", "trt1", "rtr2"),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal2[c(9, 10, 5, 6)],
  upstream = 1500,
  downstream = 1500
)
p2 <- plot_bw_profile(
  c(mocks_bigwigs, pds_bigwigs),
  peak_cats[[2]],
  labels = c("mock1", "mock2", "trt1", "rtr2"),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal2[c(9, 10, 5, 6)],
  upstream = 1500,
  downstream = 1500
)
p3 <- plot_bw_profile(
  c(mocks_bigwigs, pds_bigwigs),
  peak_cats[[3]],
  labels = c("mock1", "mock2", "trt1", "rtr2"),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal2[c(9, 10, 5, 6)],
  upstream = 1500,
  downstream = 1500
)
p4 <- plot_bw_profile(
  c(mocks_bigwigs, pds_bigwigs),
  peak_cats[[4]],
  labels = c("mock1", "mock2", "trt1", "rtr2"),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal2[c(9, 10, 5, 6)],
  upstream = 1500,
  downstream = 1500
)

ggarrange(p1, p2, p3, p4, ncol = 4, nrow = 1)
p1 <- plot_bw_profile(
  c(mocks_bigwigs, pds_bigwigs),
  peak_cats[[1]],
  labels = c("mock1", "mock2", "trt1", "rtr2"),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal2[c(9, 10, 3, 4)],
  upstream = 1500,
  downstream = 1500
)
p2 <- plot_bw_profile(
  c(mocks_bigwigs, pds_bigwigs),
  peak_cats[[2]],
  labels = c("mock1", "mock2", "trt1", "rtr2"),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal2[c(9, 10, 3, 4)],
  upstream = 1500,
  downstream = 1500
)
p3 <- plot_bw_profile(
  c(mocks_bigwigs, pds_bigwigs),
  peak_cats[[3]],
  labels = c("mock1", "mock2", "trt1", "rtr2"),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal2[c(9, 10, 3, 4)],
  upstream = 1500,
  downstream = 1500
)
p4 <- plot_bw_profile(
  c(mocks_bigwigs, pds_bigwigs),
  peak_cats[[4]],
  labels = c("mock1", "mock2", "trt1", "rtr2"),
  mode = "center",
  show_error = T,
  verbose = F,
  remove_top = 0.001,
  colors = mypal2[c(9, 10, 3, 4)],
  upstream = 1500,
  downstream = 1500
)

ggarrange(p1, p2, p3, p4, ncol = 4, nrow = 1)

cen we learn something from the genes with top-most increase in CTCF?

sigup.pds <- results[results$deseq.sigup.pds, ]
sigup.pdc <- results[results$deseq.sigup.pdc, ]

#export.bed(sigup.pds,"peaks_sigup_pds.bed")
#export.bed(sigup.pds,"peaks_sigup_pds.bed")
gghistogram(results, "width", add = "median", fill = "class")

Distance-based analysis

G4_bed <- import('../data/G4_CnT/G4_WT_peaks.narrowPeak')
ATAC_bed <- import('../data/ATAC-seq/ATAC_seq_mESC_Martire_peaks.narrowPeak')
pro_bed <- import('../data/regions/promoters_geneSymbol.mm10.bed')

G4_bed <- bedscout::annotate_overlapping_features(G4_bed, pro_bed, name_field = "name")

G4_bed$name <- "G4"
G4_bed$name[!is.na(G4_bed$nearby_features)] <- "G4pro"
G4_bed$name[grepl("pro", G4_bed$name)] <- "G4pro"
nearest_G4_1kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4_bed,
  distance_cutoff = 1000,
  ignore.strand = T,
  name_field = "name"
)
nearest_G4_2.5kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4_bed,
  distance_cutoff = 2500,
  ignore.strand = T,
  name_field = "name"
)
nearest_G4_5kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4_bed,
  distance_cutoff = 5000,
  ignore.strand = T,
  name_field = "name"
)
nearest_G4_10kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4_bed,
  distance_cutoff = 10000,
  ignore.strand = T,
  name_field = "name"
)
nearest_G4_50kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4_bed,
  distance_cutoff = 50000,
  ignore.strand = T,
  name_field = "name"
)

ctcf$nearest_G4 <- factor(">50kb",
                          levels = c("<1kb", "<2.5kb", "<5kb", "<10kb", "<50kb", ">50kb"))
ctcf$nearest_G4[!is.na(nearest_G4_50kb$nearby_features)] <- "<50kb"
ctcf$nearest_G4[!is.na(nearest_G4_10kb$nearby_features)] <- "<10kb"
ctcf$nearest_G4[!is.na(nearest_G4_5kb$nearby_features)] <- "<5kb"
ctcf$nearest_G4[!is.na(nearest_G4_2.5kb$nearby_features)] <- "<2.5kb"
ctcf$nearest_G4[!is.na(nearest_G4_1kb$nearby_features)] <- "<1kb"

ctcf$nearest_G4_type <- "none"
ctcf$nearest_G4_type[!is.na(nearest_G4_50kb$nearby_features)] <- nearest_G4_50kb$nearby_features[!is.na(nearest_G4_50kb$nearby_features)]
ctcf$nearest_G4_type[!is.na(nearest_G4_10kb$nearby_features)] <- nearest_G4_10kb$nearby_features[!is.na(nearest_G4_10kb$nearby_features)]
ctcf$nearest_G4_type[!is.na(nearest_G4_5kb$nearby_features)] <- nearest_G4_5kb$nearby_features[!is.na(nearest_G4_5kb$nearby_features)]
ctcf$nearest_G4_type[!is.na(nearest_G4_2.5kb$nearby_features)] <- nearest_G4_2.5kb$nearby_features[!is.na(nearest_G4_2.5kb$nearby_features)]
ctcf$nearest_G4_type[!is.na(nearest_G4_1kb$nearby_features)] <- nearest_G4_1kb$nearby_features[!is.na(nearest_G4_1kb$nearby_features)]

ctcf$nearest_G4_type[grep("pro", ctcf$nearest_G4_type)] <- "G4pro"

results$nearest_G4 <- ctcf$nearest_G4
results$nearest_G4_type <- ctcf$nearest_G4_type
table(results$nearest_G4)
table(results$nearest_G4_type)
table(results$nearest_G4, results$nearest_G4_type)
ggviolin(
  results,
  x = "nearest_G4",
  y = "mean.mock",
  fill = mypal[1],
  add = "median_iqr"
) + coord_cartesian(ylim = c(0, 10)) +
  stat_compare_means(label.y = 8,
                     label.x = 3,
                     size = 3) +
  geom_hline(yintercept = 0, linetype = "dotted")
ggsave(glue("{plot_folder}Violin_CTCF_signal_by_G4distance.pdf"),
       plot = last_plot())
ggviolin(
  results,
  x = "nearest_G4",
  y = "deseq.lfc.pds",
  fill = mypal[1],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-4, 4)) + geom_hline(yintercept = 0, linewidth = 0.2) +
  geom_hline(
    yintercept = median(results$deseq.lfc.pds[results$nearest_G4 == "<1kb"]),
    linetype = "dotted",
    linewidth = 0.2
  ) +
  stat_compare_means(label.y = 3,
                     label.x = 2,
                     size = 3)
ggsave(glue("{plot_folder}Violin_CTCF_PDS_lfc_by_G4distance.pdf"),
       plot = last_plot())
nearest_G4_stats = compare_means(deseq.lfc.pds ~ nearest_G4, results)
nearest_G4_stats
write_tsv(nearest_G4_stats,
          glue("{stat_output}pds_G4distance_plots-statistics.tsv"))
ggviolin(
  results,
  x = "nearest_G4",
  y = "deseq.lfc.pdc",
  fill = mypal[1],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-2, 2)) + geom_hline(yintercept = 0, linewidth = 0.2) + geom_hline(
  yintercept = mean(results$deseq.lfc.pdc[results$nearest_G4 == "<1kb"]),
  linetype = "dotted",
  linewidth = 0.2
)
ggsave(glue("{plot_folder}Violin_CTCF_PhenDC3_lfc_by_G4distance.pdf"), plot = last_plot())
nearest_G4_stats = compare_means(deseq.lfc.pdc ~ nearest_G4, results)
nearest_G4_stats
write_tsv(nearest_G4_stats, glue("{stat_output}phendc_G4distance_plots-statistics.tsv"))
ggviolin(
  results,
  x = "nearest_G4",
  y = "deseq.lfc.pds",
  fill = "nearest_G4_type",
  palette = mypal[c(1, 3, 5)],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-2, 4)) + geom_hline(yintercept = 0, linewidth = 0.2) + geom_hline(
  yintercept = mean(results$deseq.lfc.pds[results$nearest_G4 == "<1kb"]),
  linetype = "dotted",
  linewidth = 0.2
) +
  stat_compare_means(aes(group = nearest_G4_type))
ggsave(glue("{plot_folder}Violin_CTCF_PDS_lfc_by_G4distance_pro.pdf"),
       plot = last_plot())
compare_means(deseq.lfc.pds ~ nearest_G4, results[results$nearest_G4_type ==
                                                    "G4", ])
compare_means(deseq.lfc.pds ~ nearest_G4, results[results$nearest_G4_type ==
                                                    "G4", ]) %>%
  write_tsv(.,
            glue(
              "{stat_output}pds_G4distance_plots-nearest_G4-statistics.tsv"
            ))
compare_means(deseq.lfc.pds ~ nearest_G4, results[results$nearest_G4_type ==
                                                    "G4pro", ])
compare_means(deseq.lfc.pds ~ nearest_G4, results[results$nearest_G4_type ==
                                                    "G4pro", ]) %>%
  write_tsv(.,
            glue(
              "{stat_output}pds_G4distance_plots-nearest_G4pro-statistics.tsv"
            ))
ggviolin(
  results,
  x = "nearest_G4",
  y = "deseq.lfc.pdc",
  fill = "nearest_G4_type",
  palette = mypal[c(1, 3, 5)],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-2, 2)) + geom_hline(yintercept = 0, linewidth = 0.2) + geom_hline(
  yintercept = mean(results$deseq.lfc.pdc[results$nearest_G4 == "<1kb"]),
  linetype = "dotted",
  linewidth = 0.2
)
ggsave(glue(
  "{plot_folder}Violin_CTCF_PhenDC3_lfc_by_G4distance_pro.pdf"
),
plot = last_plot())
compare_means(deseq.lfc.pdc ~ nearest_G4, results[results$nearest_G4_type ==
                                                    "G4", ])
compare_means(deseq.lfc.pdc ~ nearest_G4, results[results$nearest_G4_type ==
                                                    "G4", ]) %>%
  write_tsv(.,
            glue(
              "{stat_output}phendc_G4distance_plots-nearest_G4-statistics.tsv"
            ))
compare_means(deseq.lfc.pdc ~ nearest_G4, results[results$nearest_G4_type ==
                                                    "G4pro", ])
compare_means(deseq.lfc.pdc ~ nearest_G4, results[results$nearest_G4_type ==
                                                    "G4pro", ]) %>%
  write_tsv(.,
            glue(
              "{stat_output}phendc_G4distance_plots-nearest_G4pro-statistics.tsv"
            ))

Distance-based analysis, this time with predicted G4 motifs, not experimental peaks

#results <- read.table(glue("{result_folder}foldchange_results.txt"))
results$class <- factor(results$class, levels = c("CTCF_and_G4", "CTCF_not_G4"))
G4_bed <- import('../data/G4_CnT/G4_WT_peaks.narrowPeak')
G4_bed$name <- "peak"
G4pred_bed <- import('../data/predG4/mm10_canonical_G4_PQS-regex.bed')
ATAC_bed <- import('../data/ATAC-seq/ATAC_seq_mESC_Martire_peaks.narrowPeak')
pro_bed <- import('../data/regions/promoters_geneSymbol.mm10.bed')

G4pred_bed <- bedscout::annotate_overlapping_features(G4pred_bed, G4_bed, name_field = "name")

G4pred_bed$name <- "G4pred"
G4pred_bed$name[grepl("peak", G4pred_bed$nearby_features)] <- "G4exp"

table(G4pred_bed$name)
nearest_G4_0kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4pred_bed,
  distance_cutoff = 0,
  ignore.strand = T,
  name_field = "name"
)
nearest_G4_1kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4pred_bed,
  distance_cutoff = 1000,
  ignore.strand = T,
  name_field = "name"
)
nearest_G4_2.5kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4pred_bed,
  distance_cutoff = 2500,
  ignore.strand = T,
  name_field = "name"
)
nearest_G4_5kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4pred_bed,
  distance_cutoff = 5000,
  ignore.strand = T,
  name_field = "name"
)
nearest_G4_10kb <- bedscout::annotate_nearby_features(
  ctcf,
  G4pred_bed,
  distance_cutoff = 10000,
  ignore.strand = T,
  name_field = "name"
)


ctcf$nearest_G4 <- factor(">10kb",
                          levels = c("0kb", "<1kb", "<2.5kb", "<5kb", "<10kb", ">10kb"))
ctcf$nearest_G4[!is.na(nearest_G4_10kb$nearby_features)] <- "<10kb"
ctcf$nearest_G4[!is.na(nearest_G4_5kb$nearby_features)] <- "<5kb"
ctcf$nearest_G4[!is.na(nearest_G4_2.5kb$nearby_features)] <- "<2.5kb"
ctcf$nearest_G4[!is.na(nearest_G4_1kb$nearby_features)] <- "<1kb"
ctcf$nearest_G4[!is.na(nearest_G4_0kb$nearby_features)] <- "0kb"

results$nearest_G4 <- ctcf$nearest_G4
table(results$nearest_G4)
table(results$nearest_G4, results$pro)
mdf <- reshape2::melt(table(results$nearest_G4, results$pro))
ggplot(mdf, aes(Var1, Var2, fill = value)) +
  geom_tile(show.legend = F) + geom_text(aes(label = value)) +
  scale_fill_gradient(low = "white", high = "orange") + theme_minimal()
ggsave(glue("{plot_folder}Heatmap_CTCF_sites_by_predG4distance.pdf"),
       plot = last_plot())
ggviolin(
  results,
  x = "nearest_G4",
  y = "mean.mock",
  fill = mypal[1],
  add = "median_iqr"
) + coord_cartesian(ylim = c(0, 10)) + geom_hline(yintercept = 0, linetype =
                                                    "dotted") +
  stat_compare_means(
    aes(group = nearest_G4),
    label.y = 8,
    label.x = 2,
    size = 3
  )
ggsave(glue(
  "{plot_folder}Violin_CTCF_signal_by_predG4distance.pdf"),
  plot = last_plot())
ggviolin(
  results,
  x = "nearest_G4",
  y = "deseq.lfc.pds",
  fill = mypal[1],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-0.5, 1.5)) + geom_hline(yintercept = 0, linewidth = 0.2) + geom_hline(
  yintercept = median(results$deseq.lfc.pds[results$nearest_G4 == "0kb"]),
  linetype = "dotted",
  linewidth = 0.2
) +
  stat_compare_means(label.y = 1.3,
                     label.x = 3,
                     size = 2)
ggsave(glue("{plot_folder}Violin_CTCF_PDS_lfc_by_predG4distance.pdf"),
       plot = last_plot())
compare_means(deseq.lfc.pds ~ nearest_G4, results)
ggviolin(
  results,
  x = "nearest_G4",
  y = "deseq.lfc.pdc",
  fill = mypal[1],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-0.5, 1.5)) + geom_hline(yintercept = 0, linewidth = 0.2) + geom_hline(
  yintercept = mean(results$deseq.lfc.pdc[results$nearest_G4 == "0kb"]),
  linetype = "dotted",
  linewidth = 0.2
) +
  stat_compare_means(label.y = 1.3,
                     label.x = 3,
                     size = 2)
ggsave(glue(
  "{plot_folder}Violin_CTCF_PhenDC3_lfc_by_predG4distance.pdf"
),
plot = last_plot())
compare_means(deseq.lfc.pdc ~ nearest_G4, results)
ggviolin(
  results,
  x = "nearest_G4",
  y = "deseq.lfc.pds",
  fill = "pro",
  palette = mypal[c(1, 3, 5)],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-0.5, 1.5)) + geom_hline(yintercept = 0, linewidth = 0.2) + geom_hline(
  yintercept = mean(results$deseq.lfc.pds[results$nearest_G4 == "0kb"]),
  linetype = "dotted",
  linewidth = 0.2
) +
  stat_compare_means(aes(group = pro),
                     label.y = 1.3,
                     label.x = 3,
                     size = 1.5)
ggsave(glue("{plot_folder}Violin_CTCF_PDS_lfc_by_predG4distance_pro.pdf"), plot = last_plot())

```{ r } compare_means(deseq.lfc.pds ~ nearest_G4, results[results\(pro == "noPro", ]) compare_means(deseq.lfc.pds ~ nearest_G4, results[results\)pro == “noPro”, ]) %>% write_tsv(., “pds_G4distance_plots-noPro-statistics.tsv”)


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuY29tcGFyZV9tZWFucyhkZXNlcS5sZmMucGRzIH4gbmVhcmVzdF9HNCwgcmVzdWx0c1tyZXN1bHRzJHBybyA9PSBcIlByb1wiLCBdKSAlPiVcbiAgd3JpdGVfdHN2KC4sXG4gICAgICAgICAgICBnbHVlKFwie3N0YXRfb3V0cHV0fXBkc19HNGRpc3RhbmNlX3Bsb3RzLVByby1zdGF0aXN0aWNzLnRzdlwiKSlcblxuY29tcGFyZV9tZWFucyhkZXNlcS5sZmMucGRzIH4gcHJvLCBncm91cC5ieSA9IFwibmVhcmVzdF9HNFwiLCByZXN1bHRzKSAlPiVcbiAgd3JpdGVfdHN2KC4sXG4gICAgICAgICAgICBnbHVlKFxuICAgICAgICAgICAgICBcIntzdGF0X291dHB1dH1wZHNfRzRkaXN0YW5jZV9wbG90cy1iZXR3ZWVuX3Byb21fdHlwZXNfc3RhdHMudHN2XCJcbiAgICAgICAgICAgICkpXG5cbmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkcyB+IG5lYXJlc3RfRzQsIGdyb3VwLmJ5ID0gXCJwcm9cIiwgcmVzdWx0cykgJT4lXG4gIHdyaXRlX3RzdiguLFxuICAgICAgICAgICAgZ2x1ZShcbiAgICAgICAgICAgICAgXCJ7c3RhdF9vdXRwdXR9cGRzX0c0ZGlzdGFuY2VfcGxvdHMtd2l0aGluX3Byb21fdHlwZXNfc3RhdHMudHN2XCJcbiAgICAgICAgICAgICkpXG5cbmBgYCJ9 -->

```r
compare_means(deseq.lfc.pds ~ nearest_G4, results[results$pro == "Pro", ]) %>%
  write_tsv(.,
            glue("{stat_output}pds_G4distance_plots-Pro-statistics.tsv"))

compare_means(deseq.lfc.pds ~ pro, group.by = "nearest_G4", results) %>%
  write_tsv(.,
            glue(
              "{stat_output}pds_G4distance_plots-between_prom_types_stats.tsv"
            ))

compare_means(deseq.lfc.pds ~ nearest_G4, group.by = "pro", results) %>%
  write_tsv(.,
            glue(
              "{stat_output}pds_G4distance_plots-within_prom_types_stats.tsv"
            ))
ggviolin(
  results,
  x = "nearest_G4",
  y = "deseq.lfc.pdc",
  fill = "pro",
  palette = mypal[c(1, 3, 5)],
  add = "median_iqr"
) + coord_cartesian(ylim = c(-0.5, 1.5)) + geom_hline(yintercept = 0, linewidth = 0.2) + geom_hline(
  yintercept = mean(results$deseq.lfc.pdc[results$nearest_G4 == "0kb"]),
  linetype = "dotted",
  linewidth = 0.2
) +
  stat_compare_means(aes(group = pro),
                     label.y = 1.3,
                     label.x = 3,
                     size = 1.5)
ggsave(glue(
  "{plot_folder}Violin_CTCF_PhenDC3_lfc_by_predG4distance_pro.pdf"
),
plot = last_plot())
compare_means(deseq.lfc.pdc ~ nearest_G4, results[results$pro == "noPro", ]) %>%
  write_tsv(.,
            glue(
              "{stat_output}phendc_G4distance_plots-noPro-statistics.tsv"
            ))

compare_means(deseq.lfc.pdc ~ pro, group.by = "nearest_G4", results) %>%
  write_tsv(.,
            glue(
              "{stat_output}phendc_G4distance_plots-between_prom_types_stats.tsv"
            ))

compare_means(deseq.lfc.pdc ~ nearest_G4, group.by = "pro", results) %>%
  write_tsv(.,
            glue(
              "{stat_output}phendc_G4distance_plots-within_prom_types_stats.tsv"
            ))
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJkYXRhLnRhYmxlIikKbGlicmFyeSgicnRyYWNrbGF5ZXIiKQpsaWJyYXJ5KCJnZ3Jhc3RyIikKbGlicmFyeSgiZ2x1ZSIpCmxpYnJhcnkoIkRFU2VxMiIpCmxpYnJhcnkoImdncHViciIpCmxpYnJhcnkoIndpZ2dsZXNjb3V0IikKbGlicmFyeSgiZXVsZXJyIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoY29ycnBsb3QpCgojIGV4cG9ydCAKcmVzdWx0X2ZvbGRlciA9ICIuLi9yZXN1bHRzLyIKcGxvdF9mb2xkZXIgPSAiLi4vcmVzdWx0cy9wbG90cy8iCnN0YXRfb3V0cHV0ID0gIi4uL3Jlc3VsdHMvc3RhdHMvIgoKY29tYmluZWRfYmlnd2lncyA8LSBsaXN0LmZpbGVzKCIuLi9tZW5kZWxleS9GaWd1cmUyIiwiQ1RDRl9DaElQLXNlcS4rYnciLAogICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkKZ2VvX2JpZ3dpZ3MgPC0gbGlzdC5maWxlcygiLi4vbWVuZGVsZXkvRmlndXJlMiIsIkdTTS4rYnciLAogICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkKCmBgYAoKYGBge3J9CiMgY29sb3JzCm15cGFsIDwtYygiY29ybmZsb3dlcmJsdWUiLCJvcmFuZ2UiLCJyZWQyIiwiZGFya2dyZWVuIiwiIzUwNTA1MCIpCm15cGFsIDwtYygiIzAwNjE5RCIsIiNBODJBMzQiLCJvcmFuZ2UiLCJzZWFncmVlbiIsIiM1MDUwNTAiKQpteXBhbDIgPC1jKCIjMDA2MTlEIiwiIzdGQjBDRSIsIiNBODJBMzQiLCIjRDM5NDk5Iiwib3JhbmdlIiwiI0ZGRDU1QSIsInNlYWdyZWVuIiwiIzdEQkE5QyIsIiM1MDUwNTAiKQpgYGAKCmBgYHtyfQojIGRpZmYgc2lnbmFsIGZ1bmN0aW9uCmJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyA8LSBmdW5jdGlvbihncmFuZ2VzX2MxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3Jhbmdlc19jMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2MxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfYzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlc3RpbWF0ZV9zaXplX2ZhY3RvcnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzX2dyYW5nZXMgPSBGQUxTRSkgewogICMgQmluZCBmaXJzdCwgZ2V0IG51bWJlcnMgYWZ0ZXIKICBuYW1lc192YWx1ZXMgPC0gTlVMTAogIGZpZWxkcyA8LSBuYW1lcyhtY29scyhncmFuZ2VzX2MxKSkKICAKICBpZiAoIm5hbWUiICVpbiUgZmllbGRzKSB7CiAgICBuYW1lc192YWx1ZXMgPC0gbWNvbHMoZ3Jhbmdlc19jMSlbWyJuYW1lIl1dCiAgICBncmFuZ2VzX2MxIDwtIGdyYW5nZXNfYzFbLCBmaWVsZHNbZmllbGRzICE9ICJuYW1lIl1dCiAgfQogIAogIGZpZWxkcyA8LSBuYW1lcyhtY29scyhncmFuZ2VzX2MyKSkKICBpZiAoIm5hbWUiICVpbiUgZmllbGRzKSB7CiAgICBncmFuZ2VzX2MyIDwtIGdyYW5nZXNfYzJbLCBmaWVsZHNbZmllbGRzICE9ICJuYW1lIl1dCiAgfQogIAogIGN0c19kZiA8LSBjYmluZChkYXRhLmZyYW1lKGdyYW5nZXNfYzEpLCBtY29scyhncmFuZ2VzX2MyKSkKICAKICBpZiAoIWlzLm51bGwobmFtZXNfdmFsdWVzKSkgewogICAgcm93bmFtZXMoY3RzX2RmKSA8LSBuYW1lc192YWx1ZXMKICB9CiAgCiAgIyBOZWVkcyB0byBkcm9wIG5vbi1jb21wbGV0ZSBjYXNlcyBhbmQgbWF0Y2ggcm93cwogIGNvbXBsZXRlIDwtIGNvbXBsZXRlLmNhc2VzKGN0c19kZikKICBjdHNfZGYgPC0gY3RzX2RmW2NvbXBsZXRlLCBdCiAgCiAgdmFsdWVzX2RmIDwtIGN0c19kZlssIDY6bmNvbChjdHNfZGYpXSAlPiUgZHBseXI6OnNlbGVjdCh3aGVyZShpcy5udW1lcmljKSkKICBjdHMgPC0gZ2V0X25yZWFkc19jb2x1bW5zKHZhbHVlc19kZikKICAKICBjb25kaXRpb25fbGFiZWxzIDwtIGMocmVwKGxhYmVsX2MxLCBsZW5ndGgobWNvbHMoZ3Jhbmdlc19jMSkpKSwgcmVwKGxhYmVsX2MyLCBsZW5ndGgobWNvbHMoZ3Jhbmdlc19jMikpKSkKICAKICAKICBjb2xkYXRhIDwtIGRhdGEuZnJhbWUoY29sbmFtZXMoY3RzKSwgY29uZGl0aW9uID0gYXMuZmFjdG9yKGNvbmRpdGlvbl9sYWJlbHMpKQogIHByaW50KGNvbGRhdGEpCiAgCiAgZGRzIDwtIERFU2VxMjo6REVTZXFEYXRhU2V0RnJvbU1hdHJpeCgKICAgIGNvdW50RGF0YSA9IGN0cywKICAgIGNvbERhdGEgPSBjb2xkYXRhLAogICAgZGVzaWduID0gfiBjb25kaXRpb24sCiAgICByb3dSYW5nZXMgPSBncmFuZ2VzX2MxW2NvbXBsZXRlLCBdCiAgKQogIAogIAogIGlmIChlc3RpbWF0ZV9zaXplX2ZhY3RvcnMgPT0gVFJVRSkgewogICAgZGRzIDwtIERFU2VxMjo6ZXN0aW1hdGVTaXplRmFjdG9ycyhkZHMpCiAgfQogIGVsc2UgewogICAgIyBTaW5jZSBmaWxlcyBhcmUgc2NhbGVkLCB3ZSBkbyBub3Qgd2FudCB0byBlc3RpbWF0ZSBzaXplIGZhY3RvcnMKICAgIHNpemVGYWN0b3JzKGRkcykgPC0gYyhyZXAoMSwgbmNvbChjdHMpKSkKICB9CiAgCiAgZGRzIDwtIERFU2VxMjo6ZXN0aW1hdGVEaXNwZXJzaW9ucyhkZHMpCiAgZGRzIDwtIERFU2VxMjo6bmJpbm9tV2FsZFRlc3QoZGRzKQogIAogIGlmIChhc19ncmFuZ2VzKSB7CiAgICByZXN1bHQgPC0gREVTZXEyOjpyZXN1bHRzKGRkcywgZm9ybWF0ID0gIkdSYW5nZXMiLCBhbHBoYSA9IDAuMDEpCiAgICBpZiAoIWlzLm51bGwobmFtZXNfdmFsdWVzKSkgewogICAgICByZXN1bHQkbmFtZSA8LSBuYW1lc192YWx1ZXNbY29tcGxldGVdCiAgICB9CiAgICAKICB9CiAgZWxzZSB7CiAgICAjIHJlc3VsdCA8LSByZXN1bHRzKGRkcywgZm9ybWF0PSJEYXRhRnJhbWUiKQogICAgcmVzdWx0IDwtIGRkcwogIH0KICAKICByZXN1bHQKfQoKZ2V0X25yZWFkc19jb2x1bW5zIDwtIGZ1bmN0aW9uKGRmLCBsZW5ndGhfZmFjdG9yID0gMTAwKSB7CiAgIyBDb252ZXJ0IG1lYW4gY292ZXJhZ2VzIHRvIHJvdW5kIGludGVnZXIgcmVhZCBudW1iZXJzCiAgY3RzIDwtIGFzLm1hdHJpeChkZikKICBjdHMgPC0gYXMubWF0cml4KGN0c1tjb21wbGV0ZS5jYXNlcyhjdHMpLCBdKQogIGN0cyA8LSByb3VuZChjdHMgKiBsZW5ndGhfZmFjdG9yKQogIGN0cwp9CmBgYAoKCgpgYGB7cn0KY3RjZi5hbmQuRzQucHJvIDwtIGltcG9ydCgiLi4vcGVha3MvRzQgQ1RDRl93aXRoX3Byb21vdGVyc19zb3J0ZWQuYmVkIikKY3RjZi5ub3QuRzQucHJvIDwtIGltcG9ydCgiLi4vcGVha3MvQ1RDRi1vbmx5X3dpdGhfcHJvbW90ZXJzX3NvcnRlZC5iZWQiKQpjdGNmLmFuZC5HNC5ucHIgPC0gaW1wb3J0KCIuLi9wZWFrcy9HNCBDVENGX3dpdGhvdXRfcHJvbW90ZXJzX3NvcnRlZC5iZWQiKQpjdGNmLm5vdC5HNC5ucHIgPC0gaW1wb3J0KCIuLi9wZWFrcy9DVENGLW9ubHlfd2l0aG91dF9wcm9tb3RlcnNfc29ydGVkLmJlZCIpCgpjdGNmLmFuZC5HNC5wcm8kY2xhc3MgPC0gIkNUQ0ZfYW5kX0c0IgpjdGNmLm5vdC5HNC5wcm8kY2xhc3MgPC0gIkNUQ0Zfbm90X0c0IgpjdGNmLmFuZC5HNC5ucHIkY2xhc3MgPC0gIkNUQ0ZfYW5kX0c0IgpjdGNmLm5vdC5HNC5ucHIkY2xhc3MgPC0gIkNUQ0Zfbm90X0c0IgpjdGNmLmFuZC5HNC5wcm8kcHJvIDwtICJQcm8iCmN0Y2Yubm90Lkc0LnBybyRwcm8gPC0gIlBybyIKY3RjZi5hbmQuRzQubnByJHBybyA8LSAibm9Qcm8iCmN0Y2Yubm90Lkc0Lm5wciRwcm8gPC0gIm5vUHJvIgoKY3RjZi5hbmQuRzQgPC0gYyhjdGNmLmFuZC5HNC5wcm8sY3RjZi5hbmQuRzQubnByKQpjdGNmLm5vdC5HNCA8LSBjKGN0Y2Yubm90Lkc0LnBybyxjdGNmLm5vdC5HNC5ucHIpCmN0Y2YgPC0gYyhjdGNmLmFuZC5HNCxjdGNmLm5vdC5HNCkKY3RjZiA8LSBzb3J0U2VxbGV2ZWxzKGN0Y2YpCmN0Y2YgPC0gc29ydChjdGNmKQpuYW1lcyhjdGNmKSA8LSBwYXN0ZTAoY3RjZiRjbGFzcywiICIsY3RjZiRwcm8pCnBlYWtzX2JlZCA8LSAiLi4vcGVha3MvQ1RDRl9HNF9pbl82X2NhdGVnb3JpZXMuYmVkIgpleHBvcnQuYmVkKGN0Y2YsIHBlYWtzX2JlZCkKYGBgCgojIyMgY2hlY2sgTUFDUyBwZWFrIHdpZHRocwpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpjdGNmLnJhdyA8LSBpbXBvcnQoIi4uL3BlYWtzL0NUQ0ZfbUVTX3BlYWtzLm5hcnJvd1BlYWsiKQpHNC5yYXcgPC0gaW1wb3J0KCIuLi9wZWFrcy9HNF9XVF9wZWFrcy5uYXJyb3dQZWFrIikKY3RjZi5yYXckY2xhc3MgPC0gIkNUQ0YiCkc0LnJhdyRjbGFzcyA8LSAiRzQiCmN0Y2YucmF3JHBybyA8LSAiTkEiCkc0LnJhdyRwcm8gPC0gIk5BIgpkZiA8LSByYmluZChhcy5kYXRhLmZyYW1lKGN0Y2YucmF3KVtjKDEsMiwzLDQsNSwxMiwxMyldLCBhcy5kYXRhLmZyYW1lKEc0LnJhdylbYygxLDIsMyw0LDUsMTIsMTMpXSxhcy5kYXRhLmZyYW1lKGN0Y2Yscm93Lm5hbWVzID0gTlVMTCkpCmdnZGVuc2l0eShkZix4PSJ3aWR0aCIseSA9ICJkZW5zaXR5Iixjb2xvciA9ICJjbGFzcyIsIGZpbGw9ImNsYXNzIiwgYWxwaGE9MC4xLCBwYWxldHRlPW15cGFsKSArIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDEwMCw2MDApKQpgYGAKCmBgYHtyfQptaW4od2lkdGgoRzQucmF3KSkKbWluKHdpZHRoKGN0Y2YucmF3KSkKbWVkaWFuKHdpZHRoKEc0LnJhdykpCm1lZGlhbih3aWR0aChjdGNmLnJhdykpCmBgYAojIyMgY2FsY3VsYXRlIGNvdmVyYWdlIG92ZXIgcGVha3MKYGBge3J9CiMgV3VsZnJpZGdlIENUQ0YgQ2hJUC1TZXEgbW9ja3MKbW9ja3NfYmlnd2lncyA9IGMoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9idy9TUlIyMzk1ODM4N19HU003MTE2Mjc3X0UxNF9Nb2NrX0NUQ0ZfUmVwMV9NdXNfbXVzY3VsdXNfQ2hJUC1TZXEuQ1BNbm9ybS5idyIsCiAgICAgICAgICAiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2J3L1NSUjIzOTU4Mzg2X0dTTTcxMTYyNzhfRTE0X01vY2tfQ1RDRl9SZXAyX011c19tdXNjdWx1c19DaElQLVNlcS5DUE1ub3JtLmJ3IikKCiMgUERTCiMgV3VsZnJpZGdlIENUQ0YgQ2hJUC1TZXEKcGRzX2JpZ3dpZ3MgPSBjKCIuLi9kYXRhL0N1dE5UYWdfQ2hJUC1TZXEvYncvU1JSMjM5NTgzODVfR1NNNzExNjI3OV9FMTRfUERTX0NUQ0ZfUmVwMV9NdXNfbXVzY3VsdXNfQ2hJUC1TZXEuQ1BNbm9ybS5idyIsCiAgICAgICAgICAgICAgICAiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2J3L1NSUjIzOTU4Mzg0X0dTTTcxMTYyODBfRTE0X1BEU19DVENGX1JlcDJfTXVzX211c2N1bHVzX0NoSVAtU2VxLkNQTW5vcm0uYnciKQoKcGRjX2JpZ3dpZ3MgPSBjKCIuLi9kYXRhL0N1dE5UYWdfQ2hJUC1TZXEvYncvU1JSMjM5NTgzODNfR1NNNzExNjI4MV9FMTRfUGhlbkRDM19DVENGX1JlcDFfTXVzX211c2N1bHVzX0NoSVAtU2VxLkNQTW5vcm0uYnciLAogICAgICAgICAgICAgICAgIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9idy9TUlIyMzk1ODM4Ml9HU003MTE2MjgyX0UxNF9QaGVuREMzX0NUQ0ZfUmVwMl9NdXNfbXVzY3VsdXNfQ2hJUC1TZXEuQ1BNbm9ybS5idyIpCgpHNF9iaWd3aWdzID0gYygiLi4vbWVuZGVsZXkvRmlndXJlMS9HNF9DVVQtVGFnX3RoaXNTdHVkeS5idyIpCgpjb3YubW9ja3MgPC0gYndfbG9jaShtb2Nrc19iaWd3aWdzLHBlYWtzX2JlZCxsYWJlbHM9YygibW9ja18xIiwibW9ja18yIikpCmNvdi5wZHMgPC0gYndfbG9jaShwZHNfYmlnd2lncyxwZWFrc19iZWQsbGFiZWxzPWMoIlBEU18xIiwiUERTXzIiKSkKY292LnBkYyA8LSBid19sb2NpKHBkY19iaWd3aWdzLHBlYWtzX2JlZCxsYWJlbHM9YygiUGhlbkRDM18xIiwiUGhlbkRDM18yIikpCmNvdi5HNCA8LSBid19sb2NpKEc0X2JpZ3dpZ3MscGVha3NfYmVkLGxhYmVscz1jKCJHNF9OVCIpKQpjb3YuY29tYmluZWQgPC0gYndfbG9jaShjb21iaW5lZF9iaWd3aWdzLHBlYWtzX2JlZCxsYWJlbHM9YygibW9jayIsIlBEUyIsIlBoZW5EQzMiKSkKY292LmdlbyA8LSBid19sb2NpKGdlb19iaWd3aWdzLHBlYWtzX2JlZCxsYWJlbHM9YygiR0VPX21vY2siLCJHRU9fUERTIiwiR0VPX1BoZW5EQzMiKSkKYGBgCgojIyMgcXVpY2sgY29tcGFyaXNvbiBvbiBkZXBvc2l0ZWQgYW5kIHJlcHJvY2Vzc2VkIGJpZ3dpZyBmaWxlcwpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmNvcnJfZGYgPC0gZGF0YS5mcmFtZShkYXRhLmZyYW1lKGNvdi5jb21iaW5lZClbLGMoOSw2LDcsOCldLGRhdGEuZnJhbWUoY292LmdlbylbLDY6OF0sZGF0YS5mcmFtZShjb3YubW9ja3MpWyw2OjddLGRhdGEuZnJhbWUoY292LnBkcylbLDY6N10sZGF0YS5mcmFtZShjb3YucGRjKVssNjo3XSkKcmVzIDwtIGNvcihjb3JyX2RmWywyOjEzXSkKY29ycnBsb3QocmVzLCB0eXBlID0gInVwcGVyIiwgb3JkZXIgPSAiaGNsdXN0Iix0bC5jb2wgPSAiYmxhY2siLCB0bC5zcnQgPSA0NSxhZGRDb2VmLmNvbCA9ICdibGFjaycsdGwucG9zID0gJ2QnLCAgICBjbC5wb3MgPSAnbicsIGNvbC5saW09YygwLjkzLCAxKSxpcy5jb3JyID0gRiwgbWV0aG9kID0gJ2NvbG9yJykKYGBgCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTl9CnAxIDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3NbMV0scGRzX2JpZ3dpZ3NbMV0scGRjX2JpZ3dpZ3NbMV0pLGxvY2kgPSAiLi4vcGVha3MvRzQgQ1RDRl93aXRoX3Byb21vdGVyc19zb3J0ZWQuYmVkIixtb2RlID0gImNlbnRlciIsdmVyYm9zZSA9IEYpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDIuNCkpCnAyIDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3NbMl0scGRzX2JpZ3dpZ3NbMl0scGRjX2JpZ3dpZ3NbMl0pLGxvY2kgPSAiLi4vcGVha3MvRzQgQ1RDRl93aXRoX3Byb21vdGVyc19zb3J0ZWQuYmVkIixtb2RlID0gImNlbnRlciIsdmVyYm9zZSA9IEYpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDIuNCkpCnAzIDwtIHBsb3RfYndfcHJvZmlsZShid2ZpbGVzID0gY29tYmluZWRfYmlnd2lncyxsb2NpID0gIi4uL3BlYWtzL0c0IENUQ0Zfd2l0aF9wcm9tb3RlcnNfc29ydGVkLmJlZCIsbW9kZSA9ICJjZW50ZXIiLHZlcmJvc2UgPSBGKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwyLjQpKQpnZ2FycmFuZ2UocDEscDIscDMsIG5jb2w9MykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD02fQpwMSA8LSBwbG90X2J3X3Byb2ZpbGUoYndmaWxlcyA9IGdlb19iaWd3aWdzLGxvY2kgPSAiLi4vcGVha3MvRzQgQ1RDRl93aXRoX3Byb21vdGVyc19zb3J0ZWQuYmVkIixtb2RlID0gImNlbnRlciIsdmVyYm9zZSA9IEYpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDUpKQpwMiA8LSBwbG90X2J3X3Byb2ZpbGUoYndmaWxlcyA9IGNvbWJpbmVkX2JpZ3dpZ3MsbG9jaSA9ICIuLi9wZWFrcy9HNCBDVENGX3dpdGhfcHJvbW90ZXJzX3NvcnRlZC5iZWQiLG1vZGUgPSAiY2VudGVyIix2ZXJib3NlID0gRikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsMi42KSkKZ2dhcnJhbmdlKHAxLHAyLCBuY29sPTIpCmBgYApgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD02fQpwMSA8LSBwbG90X2J3X3Byb2ZpbGUoYndmaWxlcyA9IGdlb19iaWd3aWdzLGxvY2kgPSAiLi4vcGVha3MvQ1RDRi1vbmx5X3dpdGhfcHJvbW90ZXJzX3NvcnRlZC5iZWQiLG1vZGUgPSAiY2VudGVyIix2ZXJib3NlID0gRikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNSkpCnAyIDwtIHBsb3RfYndfcHJvZmlsZShid2ZpbGVzID0gY29tYmluZWRfYmlnd2lncyxsb2NpID0gIi4uL3BlYWtzL0NUQ0Ytb25seV93aXRoX3Byb21vdGVyc19zb3J0ZWQuYmVkIixtb2RlID0gImNlbnRlciIsdmVyYm9zZSA9IEYpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDIuNikpCmdnYXJyYW5nZShwMSxwMiwgbmNvbD0yKQpgYGAKYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9OX0KcDEgPC0gcGxvdF9id19sb2NpX3NjYXR0ZXIobW9ja3NfYmlnd2lnc1sxXSxtb2Nrc19iaWd3aWdzWzJdLCBsb2NpID0gIi4uL3BlYWtzL0c0IENUQ0Zfd2l0aF9wcm9tb3RlcnNfc29ydGVkLmJlZCIsIHZlcmJvc2UgPSBGKQpwMiA8LSBwbG90X2J3X2xvY2lfc2NhdHRlcihwZHNfYmlnd2lnc1sxXSxwZHNfYmlnd2lnc1syXSwgbG9jaSA9ICIuLi9wZWFrcy9HNCBDVENGX3dpdGhfcHJvbW90ZXJzX3NvcnRlZC5iZWQiLCB2ZXJib3NlID0gRikKcDMgPC0gcGxvdF9id19sb2NpX3NjYXR0ZXIocGRjX2JpZ3dpZ3NbMV0scGRjX2JpZ3dpZ3NbMl0sIGxvY2kgPSAiLi4vcGVha3MvRzQgQ1RDRl93aXRoX3Byb21vdGVyc19zb3J0ZWQuYmVkIiwgdmVyYm9zZSA9IEYpCmdnYXJyYW5nZShwMSxwMixwMywgbmNvbD0zKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTl9CnAxIDwtIHBsb3RfYndfbG9jaV9zY2F0dGVyKGNvbWJpbmVkX2JpZ3dpZ3NbMV0sY29tYmluZWRfYmlnd2lnc1syXSwgbG9jaSA9ICIuLi9wZWFrcy9HNCBDVENGX3dpdGhfcHJvbW90ZXJzX3NvcnRlZC5iZWQiLCB2ZXJib3NlID0gRikKcDIgPC0gcGxvdF9id19sb2NpX3NjYXR0ZXIoY29tYmluZWRfYmlnd2lnc1syXSxjb21iaW5lZF9iaWd3aWdzWzNdLCBsb2NpID0gIi4uL3BlYWtzL0c0IENUQ0Zfd2l0aF9wcm9tb3RlcnNfc29ydGVkLmJlZCIsIHZlcmJvc2UgPSBGKQpwMyA8LSBwbG90X2J3X2xvY2lfc2NhdHRlcihjb21iaW5lZF9iaWd3aWdzWzFdLGNvbWJpbmVkX2JpZ3dpZ3NbM10sIGxvY2kgPSAiLi4vcGVha3MvRzQgQ1RDRl93aXRoX3Byb21vdGVyc19zb3J0ZWQuYmVkIiwgdmVyYm9zZSA9IEYpCmdnYXJyYW5nZShwMSxwMixwMywgbmNvbD0zKQpgYGAKCgpgYGB7cn0KcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogIGFzLmRhdGEuZnJhbWUoY292Lm1vY2tzKSwKICBhcy5kYXRhLmZyYW1lKGNvdi5wZHMpWzY6N10sCiAgYXMuZGF0YS5mcmFtZShjb3YucGRjKVs2OjddLAogIGFzLmRhdGEuZnJhbWUoY292Lkc0KVs2XSwKICByYXcubGZjLnBkc18xID0gbG9nMihjb3YucGRzJFBEU18xIC8gY292Lm1vY2tzJG1vY2tfMSksCiAgcmF3LmxmYy5wZHNfMiA9IGxvZzIoY292LnBkcyRQRFNfMiAvIGNvdi5tb2NrcyRtb2NrXzIpLAogIHJhdy5sZmMucGRjXzEgPSBsb2cyKGNvdi5wZHMkUERTXzEgLyBjb3YubW9ja3MkbW9ja18xKSwKICByYXcubGZjLnBkY18yID0gbG9nMihjb3YucGRjJFBoZW5EQzNfMiAvIGNvdi5tb2NrcyRtb2NrXzIpLAogIHJhdy5sZmMucGRzID0gbG9nMihyb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5wZHMpWzY6N10pIC8gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YubW9ja3MpWzY6N10pKSwKICByYXcubGZjLnBkYyA9IGxvZzIocm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YucGRjKVs2OjddKSAvIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292Lm1vY2tzKVs2OjddKSksCiAgbWVhbi5tb2NrID0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YubW9ja3MpWzY6N10pLAogIG1lYW4ucGRzID0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YucGRzKVs2OjddKSwKICBtZWFuLnBkYyA9IHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LnBkYylbNjo3XSkKKQoKY292Lm1vY2tzJG5hbWUgPC0gTlVMTApjb3YucGRzJG5hbWUgPC0gTlVMTApjb3YucGRjJG5hbWUgPC0gTlVMTAoKZGVfcGRzIDwtIGJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyhjb3YubW9ja3MsIGNvdi5wZHMsICJNb2NrIiwgIlBEUyIpCmxmY19wZHMgPSBERVNlcTI6OmxmY1NocmluayhkZV9wZHMsIGNvZWYgPSAiY29uZGl0aW9uX1BEU192c19Nb2NrIiwgdHlwZSA9ICJhcGVnbG0iKQoKZGVfcGRjIDwtIGJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyhjb3YubW9ja3MsIGNvdi5wZGMsICJNb2NrIiwgIlBoZW5EQzMiKQpsZmNfcGRjID0gREVTZXEyOjpsZmNTaHJpbmsoZGVfcGRjLCBjb2VmID0gImNvbmRpdGlvbl9QaGVuREMzX3ZzX01vY2siLCB0eXBlID0gImFwZWdsbSIpCgpyZXN1bHRzJGRlc2VxLmxmYy5wZHMgPC0gcmVzdWx0cyhkZV9wZHMpJGxvZzJGb2xkQ2hhbmdlCnJlc3VsdHMkZGVzZXEubGZjcy5wZHMgPC0gbGZjX3BkcyRsb2cyRm9sZENoYW5nZQpyZXN1bHRzJGRlc2VxLnBhZGoucGRzIDwtIGxmY19wZHMkcGFkagpyZXN1bHRzJGRlc2VxLm1lYW4ucGRzIDwtIGxvZzIobGZjX3BkcyRiYXNlTWVhbikKcmVzdWx0cyRkZXNlcS5zaWcucGRzIDwtIGxmY19wZHMkcHZhbHVlIDwgMC4wNQoKcmVzdWx0cyRkZXNlcS5sZmMucGRjIDwtIHJlc3VsdHMoZGVfcGRjKSRsb2cyRm9sZENoYW5nZQpyZXN1bHRzJGRlc2VxLmxmY3MucGRjIDwtIGxmY19wZGMkbG9nMkZvbGRDaGFuZ2UKcmVzdWx0cyRkZXNlcS5wYWRqLnBkYyA8LSBsZmNfcGRjJHBhZGoKcmVzdWx0cyRkZXNlcS5tZWFuLnBkYyA8LSBsb2cyKGxmY19wZGMkYmFzZU1lYW4pCnJlc3VsdHMkZGVzZXEuc2lnLnBkYyA8LSBsZmNfcGRjJHB2YWx1ZSA8IDAuMDUKCnJlc3VsdHMkY2xhc3MgPC0gZ3N1YigiIC4rIiwgIiIsIHJlc3VsdHMkbmFtZSkKcmVzdWx0cyRwcm8gPC0gZ3N1YigiLisgIiwgIiIsIHJlc3VsdHMkbmFtZSkKcmVzdWx0cyRwcm8gPC0gZmFjdG9yKHJlc3VsdHMkcHJvLCBsZXZlbHMgPSBjKCJQcm8iLCAibm9Qcm8iKSkKcmVzdWx0cyRjbGFzcyA8LSBmYWN0b3IocmVzdWx0cyRjbGFzcywgbGV2ZWxzID0gYygiQ1RDRl9hbmRfRzQiLCAiQ1RDRl9ub3RfRzQiKSkKCnJlc3VsdHMkbG9nMi5tb2NrIDwtIGxvZzIocmVzdWx0cyRtZWFuLm1vY2spCnJlc3VsdHMkbG9nMi5wZHMgPC0gbG9nMihyZXN1bHRzJG1lYW4ucGRzKQpyZXN1bHRzJGxvZzIucGRjIDwtIGxvZzIocmVzdWx0cyRtZWFuLnBkYykKcmVzdWx0cyRsb2cyLkc0IDwtIGxvZzIocmVzdWx0cyRHNF9OVCkKCnJlc3VsdHMkZGVzZXEuc2lndXAucGRzIDwtIHJlc3VsdHMkZGVzZXEuc2lnLnBkcyAmCiAgcmVzdWx0cyRkZXNlcS5sZmMucGRzID4gMApyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkYyA8LSByZXN1bHRzJGRlc2VxLnNpZy5wZGMgJgogIHJlc3VsdHMkZGVzZXEubGZjLnBkYyA+IDAKYGBgCgpgYGB7cn0Kd3JpdGUudGFibGUocmVzdWx0cywgZ2x1ZSgie3Jlc3VsdF9mb2xkZXJ9Zm9sZGNoYW5nZV9yZXN1bHRzLnR4dCIpKQp0YWJsZShyZXN1bHRzJG5hbWUpCmBgYAoKYGBge3J9CiNyZXN1bHRzIDwtIHJlYWQudGFibGUoImZvbGRjaGFuZ2VfcmVzdWx0cy50eHQiKQpyZXN1bHRzJGNsYXNzIDwtIGZhY3RvcihyZXN1bHRzJGNsYXNzLCBsZXZlbHMgPSBjKCJDVENGX2FuZF9HNCIsICJDVENGX25vdF9HNCIpKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpwIDwtIGdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJjbGFzcyIsCiAgeSA9ICJtZWFuLm1vY2siLAogIGZpbGwgPSAiY2xhc3MiLAogIHBhbGV0dGUgPSBteXBhbCwKICBhZGQgPSAibWVkaWFuX2lxciIKKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAxMCkpCmFubm90YXRlX2ZpZ3VyZShwLCBmaWcubGFiID0gIkNUQ0Ygc2lnbmFsIGJ5IGNsYXNzIGluIG1vY2sgY29uZGl0aW9uLCBtZWFuIG9mIHR3byByZXBzLCBtZWRpYW4raXFyIiwgZmlnLmxhYi5zaXplID0gNikKZ2dzYXZlKGdsdWUoIntwbG90X2ZvbGRlcn1WaW9saW5fQ1RDRl9jbGFzc2VzLnBkZiIpLCBsYXN0X3Bsb3QoKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpwIDwtIGdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJjbGFzcyIsCiAgeSA9ICJtZWFuLm1vY2siLAogIGZpbGwgPSAicHJvIiwKICBwYWxldHRlID0gbXlwYWwsCiAgYWRkID0gIm1lZGlhbl9pcXIiCikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMTApKQphbm5vdGF0ZV9maWd1cmUocCwgZmlnLmxhYiA9ICJDVENGIHNpZ25hbCBieSBjbGFzcyBpbiBtb2NrIGNvbmRpdGlvbiwgbWVhbiBvZiB0d28gcmVwcywgbWVkaWFuK2lxciIsIGZpZy5sYWIuc2l6ZSA9IDYpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9VmlvbGluX0NUQ0ZfY2xhc3Nlc19wcm8ucGRmIiksCiAgICAgICBsYXN0X3Bsb3QoKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0zfQptZGYgPC0gcmVzaGFwZTI6Om1lbHQoZHBseXI6OnNlbGVjdCgKICByZXN1bHRzLAogIGMoCiAgICAiY2xhc3MiLAogICAgIm1vY2tfMSIsCiAgICAibW9ja18yIiwKICAgICJQRFNfMSIsCiAgICAiUERTXzIiLAogICAgIlBoZW5EQzNfMSIsCiAgICAiUGhlbkRDM18yIgogICkKKSkKZ2dib3hwbG90KAogIG1kZiwKICB4ID0gInZhcmlhYmxlIiwKICB5ID0gInZhbHVlIiwKICBmaWxsID0gImNsYXNzIiwKICBwYWxldHRlID0gbXlwYWwKKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAxMCkpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9Qm94cGxvdF9DVENGX3JlcHMucGRmIiksIGxhc3RfcGxvdCgpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTN9Cm1kZiA8LSByZXNoYXBlMjo6bWVsdChkcGx5cjo6c2VsZWN0KAogIHJlc3VsdHMsCiAgYygKICAgICJjbGFzcyIsCiAgICAibW9ja18xIiwKICAgICJtb2NrXzIiLAogICAgIlBEU18xIiwKICAgICJQRFNfMiIsCiAgICAiUGhlbkRDM18xIiwKICAgICJQaGVuREMzXzIiCiAgKQopKQoKbWRmX3N0YXRzX2NsYXNzID0gY29tcGFyZV9tZWFucyh2YWx1ZSB+IGNsYXNzLCBncm91cC5ieSA9ICJ2YXJpYWJsZSIsIGRhdGEgPSBtZGYpCgpnZ3Zpb2xpbigKICBtZGYsCiAgeCA9ICJ2YXJpYWJsZSIsCiAgeSA9ICJ2YWx1ZSIsCiAgZmlsbCA9ICJjbGFzcyIsCiAgcGFsZXR0ZSA9IG15cGFsLAogIGFkZCA9ICJtZWRpYW5faXFyIgopICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDEwKSkKZ2dzYXZlKGdsdWUoIntwbG90X2ZvbGRlcn1WaW9saW5fQ1RDRl9yZXBzLnBkZiIpLCBsYXN0X3Bsb3QoKSkKYGBgCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9Cm1kZiA8LSByZXNoYXBlMjo6bWVsdChkcGx5cjo6c2VsZWN0KHJlc3VsdHMsIGMoCiAgImNsYXNzIiwgImRlc2VxLmxmYy5wZHMiLCAiZGVzZXEubGZjLnBkYyIKKSkpCnAgPC0gZ2d2aW9saW4oCiAgbWRmLAogIHggPSAidmFyaWFibGUiLAogIHkgPSAidmFsdWUiLAogIGZpbGwgPSAiY2xhc3MiLAogIHBhbGV0dGUgPSBteXBhbCwKICBhZGQgPSAibWVkaWFuX2lxciIKKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRvdHRlZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKC0zLCAzKSkgKyBzdGF0X2NvbXBhcmVfbWVhbnMoYWVzKGdyb3VwID0gY2xhc3MpLCBsYWJlbC55ID0gMywgc2l6ZSA9IDIpCgphbm5vdGF0ZV9maWd1cmUocCwgZmlnLmxhYiA9ICJERVNFcSBmb2xkY2hhbmdlIG1lYW4gdHJlYXQgdnMgbWVhbiBtb2NrLCBtZWRpYW4raXFyIiwgZmlnLmxhYi5zaXplID0gNikKZ2dzYXZlKAogIGdsdWUoIntwbG90X2ZvbGRlcn1WaW9saW5fQ1RDRl9sZmMucGRmIiksCiAgbGFzdF9wbG90KCksCiAgd2lkdGggPSA1LAogIGhlaWdodCA9IDUKKQpgYGAKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcCA8LSBnZ2JveHBsb3QoCiAgbWRmLAogIHggPSAidmFyaWFibGUiLAogIHkgPSAidmFsdWUiLAogIGZpbGwgPSAiY2xhc3MiLAogIHBhbGV0dGUgPSBteXBhbAopICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZG90dGVkIikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoLTIsIDIpKQphbm5vdGF0ZV9maWd1cmUocCwgZmlnLmxhYiA9ICJERVNFcSBmb2xkY2hhbmdlIG1lYW4gdHJlYXQgdnMgbWVhbiBtb2NrLCBtZWRpYW4raXFyIiwgZmlnLmxhYi5zaXplID0gNikKZ2dzYXZlKGdsdWUoIntwbG90X2ZvbGRlcn1Cb3hwbG90X0NUQ0ZfbGZjLnBkZiIpLCBsYXN0X3Bsb3QoKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD02fQptZGYgPC0gcmVzaGFwZTI6Om1lbHQoZHBseXI6OnNlbGVjdChyZXN1bHRzLCBjKAogICJwcm8iLCAiY2xhc3MiLCAiZGVzZXEubGZjLnBkcyIsICJkZXNlcS5sZmMucGRjIgopKSkKbWRmJHBybyA8LSBmYWN0b3IobWRmJHBybywgbGV2ZWxzID0gYygiUHJvIiwgIm5vUHJvIikpCm1kZiR4IDwtIGFzLmZhY3RvcihwYXN0ZTAobWRmJGNsYXNzLCAiICIsIG1kZiR2YXJpYWJsZSkpCm1kZiR4IDwtIGZhY3RvcihtZGYkeCwgbGV2ZWxzID0gbGV2ZWxzKG1kZiR4KVtjKDIsIDEsIDQsIDMpXSkKcCA8LSBnZ3Zpb2xpbigKICBtZGYsCiAgeCA9ICJ4IiwKICB5ID0gInZhbHVlIiwKICBmaWxsID0gImNsYXNzIiwKICBwYWxldHRlID0gbXlwYWwsCiAgYWRkID0gIm1lZGlhbl9pcXIiLAogIGZhY2V0LmJ5ID0gInBybyIKKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRvdHRlZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKC0yLCAyKSkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKQphbm5vdGF0ZV9maWd1cmUocCwgZmlnLmxhYiA9ICJERVNFcSBmb2xkY2hhbmdlIG1lYW4gdHJlYXQgdnMgbWVhbiBtb2NrLCBtZWRpYW4raXFyIiwgZmlnLmxhYi5zaXplID0gNikKZ2dzYXZlKGdsdWUoIntwbG90X2ZvbGRlcn1WaW9saW5fQ1RDRl9sZmNfcHJvLnBkZiIpLCBsYXN0X3Bsb3QoKSkKYGBgCgpgYGB7cn0KbWVkIDwtIGFnZ3JlZ2F0ZShkZXNlcS5sZmMucGRzIH4gY2xhc3MsCiAgICAgICAgICAgICAgICAgZGF0YSA9IHJlc3VsdHMsCiAgICAgICAgICAgICAgICAgRlVOID0gIm1lZGlhbiIsCiAgICAgICAgICAgICAgICAgbmEucm0gPSBUKQptZWQkZGVzZXEuZmMucGRzIDwtIDIgXiBtZWQkZGVzZXEubGZjLnBkcwptZWQKYGBgCgpgYGB7cn0KbWVkIDwtIGFnZ3JlZ2F0ZShkZXNlcS5sZmMucGRzIH4gbmFtZSwKICAgICAgICAgICAgICAgICBkYXRhID0gcmVzdWx0cywKICAgICAgICAgICAgICAgICBGVU4gPSAibWVkaWFuIiwKICAgICAgICAgICAgICAgICBuYS5ybSA9IFQpCm1lZCRkZXNlcS5mYy5wZHMgPC0gMiBeIG1lZCRkZXNlcS5sZmMucGRzCm1lZApgYGAKYGBge3J9Cm1lZCA8LSBhZ2dyZWdhdGUoZGVzZXEubGZjLnBkcyB+IGNsYXNzLAogICAgICAgICAgICAgICAgIGRhdGEgPSByZXN1bHRzLAogICAgICAgICAgICAgICAgIEZVTiA9ICJtZWRpYW4iLAogICAgICAgICAgICAgICAgIG5hLnJtID0gVCkKbWVkJGRlc2VxLmZjLnBkcyA8LSAyIF4gbWVkJGRlc2VxLmxmYy5wZHMKbWVkCmBgYApgYGB7cn0KbWVkIDwtIGFnZ3JlZ2F0ZShkZXNlcS5sZmMucGRjIH4gbmFtZSwKICAgICAgICAgICAgICAgICBkYXRhID0gcmVzdWx0cywKICAgICAgICAgICAgICAgICBGVU4gPSAibWVkaWFuIiwKICAgICAgICAgICAgICAgICBuYS5ybSA9IFQpCm1lZCRkZXNlcS5mYy5wZGMgPC0gMiBeIG1lZCRkZXNlcS5sZmMucGRjCm1lZApgYGAKCmBgYHtyfQpkZXNlcV9sZmNfc3RhdHMgPSBjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZHMgfiBjbGFzcywgZGF0YSA9IHJlc3VsdHMpCmRlc2VxX2xmY19zdGF0cwp3cml0ZV90c3YoZGVzZXFfbGZjX3N0YXRzLAogICAgICAgICAgZ2x1ZSgie3N0YXRfb3V0cHV0fXBkcy1kZXNlcTJfbGZjX3N0YXRpc3RpY3MudHN2IikpCgpgYGAKCmBgYHtyfQpkZXNlcV9sZmNfc3RhdHMgPSBjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZGMgfiBjbGFzcywgZGF0YSA9IHJlc3VsdHMpCmRlc2VxX2xmY19zdGF0cwp3cml0ZV90c3YoZGVzZXFfbGZjX3N0YXRzLAogICAgICAgICAgZ2x1ZSgie3N0YXRfb3V0cHV0fXBoZW5kYy1kZXNlcTJfbGZjX3N0YXRpc3RpY3MudHN2IikpCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9M30KbWRmIDwtIHJlc2hhcGUyOjptZWx0KGRwbHlyOjpzZWxlY3QoCiAgcmVzdWx0cywKICBjKAogICAgImNsYXNzIiwKICAgICJyYXcubGZjLnBkc18xIiwKICAgICJyYXcubGZjLnBkc18yIiwKICAgICJyYXcubGZjLnBkY18xIiwKICAgICJyYXcubGZjLnBkY18yIgogICkKKSkKZ2d2aW9saW4oCiAgbWRmLAogIHggPSAidmFyaWFibGUiLAogIHkgPSAidmFsdWUiLAogIGZpbGwgPSAiY2xhc3MiLAogIHBhbGV0dGUgPSBteXBhbCwKICBhZGQgPSAibWVkaWFuX2lxciIKKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRvdHRlZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKC0zLCAzKSkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhhZXMoZ3JvdXAgPSBjbGFzcyksIGxhYmVsLnkgPSAzLjYsIHNpemUgPSAyKQpnZ3NhdmUoZ2x1ZSgie3Bsb3RfZm9sZGVyfVZpb2xpbl9DVENGX2xmY19pbmRpdmlkdWFsX3JlcHMucGRmIiksIGxhc3RfcGxvdCgpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmdnZGVuc2l0eSgKICByZXN1bHRzLAogIHggPSAicmF3LmxmYy5wZHMiLAogIGNvbG9yID0gImNsYXNzIiwKICBmaWxsID0gImNsYXNzIiwKICBwYWxldHRlID0gbXlwYWwKKSArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRvdHRlZCIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2dkZW5zaXR5KAogIHJlc3VsdHMsCiAgeCA9ICJyYXcubGZjLnBkYyIsCiAgY29sb3IgPSAiY2xhc3MiLAogIGZpbGwgPSAiY2xhc3MiLAogIHBhbGV0dGUgPSBteXBhbAopICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZG90dGVkIikKYGBgCgoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2dzY2F0dGVyKAogIHJlc3VsdHMsCiAgeCA9ICJsb2cyLm1vY2siLAogIHkgPSAibG9nMi5wZHMiLAogIHNpemUgPSAxLHNoYXBlPTIwLAogIGFscGhhID0gMC4xLAogIGNvbG9yID0gImRlc2VxLnNpZy5wZHMiLAogIHBhbGV0dGUgPSBteXBhbFtjKDUsIDIpXQopCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9U2NhdHRlcl9DVENGX0RFU0VxX1BEU3ZzTW9jay5wZGYiKSwgcmFzdGVyaXplKGxhc3RfcGxvdCgpLGRwaSA9IDYwMCksd2lkdGggPSAzLCBoZWlnaHQ9IDMuMikKYGBgCmBgYHtyIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTR9Cmdnc2NhdHRlcigKICByZXN1bHRzLAogIHggPSAibG9nMi5tb2NrIiwKICB5ID0gImxvZzIucGRjIiwKICBzaXplID0gMSxzaGFwZT0yMCwKICBhbHBoYSA9IDAuMSwKICBjb2xvciA9ICJkZXNlcS5zaWcucGRjIiwKICBwYWxldHRlID0gbXlwYWxbYyg1LCAyKV0KKQpnZ3NhdmUoZ2x1ZSgie3Bsb3RfZm9sZGVyfVNjYXR0ZXJfQ1RDRl9ERVNFcV9QaGVuREMzdnNNb2NrLnBkZiIpLCByYXN0ZXJpemUobGFzdF9wbG90KCksZHBpID0gNjAwKSx3aWR0aCA9IDMsIGhlaWdodD0gMy4yKQpgYGAKYGBge3J9CnRiIDwtIHRhYmxlKHJlc3VsdHMkY2xhc3MpCmRlc2VxLnN0YXRzIDwtIGFzLmRhdGEuZnJhbWUodChhcy5tYXRyaXgodGIpKSkKZGVzZXEuc3RhdHNbMSxdIDwtIGNvbFN1bXMoZGVzZXEuc3RhdHMpCnJvd25hbWVzKGRlc2VxLnN0YXRzKSA8LSBjKCJUb3RhbCIpCmRlc2VxLnN0YXRzLnBlcmNlbnQgPC0gZGVzZXEuc3RhdHMKZGVzZXEuc3RhdHMucGVyY2VudFsxLF0gPC0gYygxMDAsMTAwKQp0YgpgYGAKCmBgYHtyfQp0YiA8LSB0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZHMgJgogICAgICAgIChyZXN1bHRzJGRlc2VxLmxmYy5wZHMgPiAwKSwKICAgICAgcmVzdWx0cyRjbGFzcykKZGVzZXEuc3RhdHMgPC0gcmJpbmQoZGVzZXEuc3RhdHMsIFBEUy5zaWcudXAgPSBhcy5kYXRhLmZyYW1lLm1hdHJpeCh0YilbMixdKQp0YgpgYGAKYGBge3J9CnRiIDwtIHByb3AudGFibGUodGFibGUocmVzdWx0cyRkZXNlcS5zaWcucGRzICYKICAgICAgICAocmVzdWx0cyRkZXNlcS5sZmMucGRzID4gMCksCiAgICAgIHJlc3VsdHMkY2xhc3MpLG1hcmdpbiA9IDIpKjEwMApkZXNlcS5zdGF0cy5wZXJjZW50IDwtIHJiaW5kKGRlc2VxLnN0YXRzLnBlcmNlbnQsIFBEUy5zaWcudXAgID0gYXMuZGF0YS5mcmFtZS5tYXRyaXgodGIpWzIsXSkKdGIKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0yLjV9CnRhYmxlKHJlc3VsdHMkZGVzZXEuc2lnLnBkcyAmCiAgICAgICAgKHJlc3VsdHMkZGVzZXEubGZjLnBkcyA+IDApLAogICAgICByZXN1bHRzJGNsYXNzKQptZGYgPC0gcmVzaGFwZTI6Om1lbHQodGFibGUoCiAgcmVzdWx0cyRkZXNlcS5zaWcucGRzICYgKHJlc3VsdHMkZGVzZXEubGZjLnBkcyA+IDApLAogIHJlc3VsdHMkY2xhc3MKKSkKZ2dwbG90KG1kZiwgYWVzKFZhcjEsIFZhcjIsIGZpbGwgPSB2YWx1ZSkpICsKICBnZW9tX3RpbGUoc2hvdy5sZWdlbmQgPSBGKSArIGdlb21fdGV4dChhZXMobGFiZWwgPSB2YWx1ZSkpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAib3JhbmdlIikgKyB0aGVtZV9taW5pbWFsKCkKYGBgCgpgYGB7cn0KdmwgPC0gbGlzdCgKICBzaWcgPSBncmVwKCJUUlVFIiwgcmVzdWx0cyRkZXNlcS5zaWd1cC5wZHMpLAogIENUQ0ZfRzQgPSBncmVwKCJhbmQiLCByZXN1bHRzJGNsYXNzKSwKICBDVENGb25seSA9IGdyZXAoIm5vdCIsIHJlc3VsdHMkY2xhc3MpCikKcGxvdChldWxlcih2bCksIHF1YW50aXRpZXMgPSBUKQpgYGAKCmBgYHtyfQp0YiA8LSB0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZGMgJgogICAgICAgIChyZXN1bHRzJGRlc2VxLmxmYy5wZGMgPiAwKSwKICAgICAgcmVzdWx0cyRjbGFzcykKZGVzZXEuc3RhdHMgPC0gcmJpbmQoZGVzZXEuc3RhdHMsIFBoZW5EQzMuc2lnLnVwID0gYXMuZGF0YS5mcmFtZS5tYXRyaXgodGIpWzIsXSkKdGIKYGBgCgpgYGB7cn0KdGIgPC0gcHJvcC50YWJsZSh0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZGMgJgogICAgICAgIChyZXN1bHRzJGRlc2VxLmxmYy5wZGMgPiAwKSwKICAgICAgcmVzdWx0cyRjbGFzcyksbWFyZ2luID0gMikqMTAwCmRlc2VxLnN0YXRzLnBlcmNlbnQgPC0gcmJpbmQoZGVzZXEuc3RhdHMucGVyY2VudCwgUGhlbkRDMy5zaWcudXAgPSBhcy5kYXRhLmZyYW1lLm1hdHJpeCh0YilbMixdKQp0YgpgYGAKCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0yLjV9CnRhYmxlKHJlc3VsdHMkZGVzZXEuc2lnLnBkYyAmCiAgICAgICAgKHJlc3VsdHMkZGVzZXEubGZjLnBkYyA+IDApLAogICAgICByZXN1bHRzJGNsYXNzKQptZGYgPC0gcmVzaGFwZTI6Om1lbHQodGFibGUoCiAgcmVzdWx0cyRkZXNlcS5zaWcucGRjICYgKHJlc3VsdHMkZGVzZXEubGZjLnBkYyA+IDApLAogIHJlc3VsdHMkY2xhc3MKKSkKZ2dwbG90KG1kZiwgYWVzKFZhcjEsIFZhcjIsIGZpbGwgPSB2YWx1ZSkpICsKICBnZW9tX3RpbGUoc2hvdy5sZWdlbmQgPSBGKSArIGdlb21fdGV4dChhZXMobGFiZWwgPSB2YWx1ZSkpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAib3JhbmdlIikgKyB0aGVtZV9taW5pbWFsKCkKYGBgCgoKYGBge3J9CnJlc3VsdHMkdWlkIDwtIHNlcSgxOm5yb3cocmVzdWx0cykpCnZsIDwtIGxpc3QoCiAgc2lnID0gZ3JlcCgiVFJVRSIsIHJlc3VsdHMkZGVzZXEuc2lndXAucGRjKSwKICBDVENGX0c0ID0gZ3JlcCgiYW5kIiwgcmVzdWx0cyRjbGFzcyksCiAgQ1RDRm9ubHkgPSBncmVwKCJub3QiLCByZXN1bHRzJGNsYXNzKQopCnBsb3QoZXVsZXIodmwpLCBxdWFudGl0aWVzID0gVCkKYGBgCiAKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9Mi41fQp0YWJsZShyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcywgcmVzdWx0cyRkZXNlcS5zaWd1cC5wZGMpCm1kZiA8LSByZXNoYXBlMjo6bWVsdCh0YWJsZShyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcywgcmVzdWx0cyRkZXNlcS5zaWd1cC5wZGMpKQpnZ3Bsb3QobWRmLCBhZXMoVmFyMSwgVmFyMiwgZmlsbCA9IHZhbHVlKSkgKwogIGdlb21fdGlsZShzaG93LmxlZ2VuZCA9IEYpICsgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHZhbHVlKSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJvcmFuZ2UiKSArIHRoZW1lX21pbmltYWwoKQpgYGAKYGBge3J9CnRiIDwtIHRhYmxlKHJlc3VsdHMkZGVzZXEuc2lndXAucGRzICYgcmVzdWx0cyRkZXNlcS5zaWd1cC5wZGMsCiAgICAgIHJlc3VsdHMkY2xhc3MpCmRlc2VxLnN0YXRzIDwtIHJiaW5kKGRlc2VxLnN0YXRzLCBib3RoLnNpZy51cCA9IGFzLmRhdGEuZnJhbWUubWF0cml4KHRiKVsyLF0pCnRiCmBgYAoKYGBge3J9CnRiIDwtIHByb3AudGFibGUodGFibGUocmVzdWx0cyRkZXNlcS5zaWd1cC5wZHMgJiByZXN1bHRzJGRlc2VxLnNpZ3VwLnBkYywKICAgICAgcmVzdWx0cyRjbGFzcyksbWFyZ2luID0gMikqMTAwCmRlc2VxLnN0YXRzLnBlcmNlbnQgPC0gcmJpbmQoZGVzZXEuc3RhdHMucGVyY2VudCwgYm90aCA9IGFzLmRhdGEuZnJhbWUubWF0cml4KHRiKVsyLF0pCnRiCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9Mi41fQp0YWJsZShyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyAmIHJlc3VsdHMkZGVzZXEuc2lndXAucGRjLCByZXN1bHRzJGNsYXNzKQptZGYgPC0gcmVzaGFwZTI6Om1lbHQodGFibGUocmVzdWx0cyRkZXNlcS5zaWd1cC5wZHMgJiByZXN1bHRzJGRlc2VxLnNpZ3VwLnBkYywgcmVzdWx0cyRjbGFzcykpCmdncGxvdChtZGYsIGFlcyhWYXIxLCBWYXIyLCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV90aWxlKHNob3cubGVnZW5kID0gRikgKyBnZW9tX3RleHQoYWVzKGxhYmVsID0gdmFsdWUpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gIm9yYW5nZSIpICsgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3IgZmlnLndpZHRoPTIuNSwgZmlnLmhlaWdodD0yLjV9CmRlc2VxLnN0YXRzJGNsYXNzIDwtIHJvd25hbWVzKGRlc2VxLnN0YXRzKSAKbWRmIDwtIHJlc2hhcGUyOjptZWx0KGRlc2VxLnN0YXRzKQpnZ3Bsb3QobWRmLCBhZXModmFyaWFibGUsIGNsYXNzLCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV90aWxlKHNob3cubGVnZW5kID0gRikgKyBnZW9tX3RleHQoYWVzKGxhYmVsID0gdmFsdWUpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gIm9yYW5nZSIpICsgdGhlbWVfbWluaW1hbCgpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9VGFibGVfQ1RDRl9ERVNFcV9TaWd1cC5wZGYiKSwgcmFzdGVyaXplKGxhc3RfcGxvdCgpLGRwaSA9IDYwMCksd2lkdGggPSAyLjUsIGhlaWdodD0gMi41KQpgYGAKYGBge3IgZmlnLndpZHRoPTIuNSwgZmlnLmhlaWdodD0yLjV9CmRlc2VxLnN0YXRzLnBlcmNlbnQkY2xhc3MgPC0gcm93bmFtZXMoZGVzZXEuc3RhdHMucGVyY2VudCkgCm1kZiA8LSByZXNoYXBlMjo6bWVsdChkZXNlcS5zdGF0cy5wZXJjZW50Wy0xLF0pCmdncGxvdChtZGYsIGFlcyh2YXJpYWJsZSwgY2xhc3MsIGZpbGwgPSB2YWx1ZSkpICsKICBnZW9tX3RpbGUoc2hvdy5sZWdlbmQgPSBGKSArIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChtZGYkdmFsdWUsMikpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gIm9yYW5nZSIpICsgdGhlbWVfbWluaW1hbCgpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9VGFibGVfQ1RDRl9ERVNFcV9TaWd1cF9wZXJjZW50LnBkZiIpLCByYXN0ZXJpemUobGFzdF9wbG90KCksZHBpID0gNjAwKSx3aWR0aCA9IDIuNSwgaGVpZ2h0PSAyLjUpCmBgYAoKYGBge3J9CnZsIDwtIGxpc3QoCiAgc2lnX1BEUyA9IGdyZXAoIlRSVUUiLCByZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyksCiAgc2lnX1BEQyA9IGdyZXAoIlRSVUUiLCByZXN1bHRzJGRlc2VxLnNpZ3VwLnBkYyksCiAgQ1RDRl9HNCA9IGdyZXAoImFuZCIsIHJlc3VsdHMkY2xhc3MpLAogIENUQ0Zvbmx5ID0gZ3JlcCgibm90IiwgcmVzdWx0cyRjbGFzcykKKQpwbG90KGV1bGVyKHZsKSwgcXVhbnRpdGllcyA9IFQpCmBgYAoKYGBge3J9CnJlc3VsdHMkdWlkIDwtIHNlcSgxOm5yb3cocmVzdWx0cykpCnZsIDwtIGxpc3QoCiAgc2lnX1BEUyA9IGdyZXAoIlRSVUUiLCByZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyksCiAgc2lnX1BEQyA9IGdyZXAoIlRSVUUiLCByZXN1bHRzJGRlc2VxLnNpZ3VwLnBkYyksCiAgQ1RDRl9HNCA9IGdyZXAoImFuZCIsIHJlc3VsdHMkY2xhc3MpCikKcGxvdChldWxlcih2bCksIHF1YW50aXRpZXMgPSBUKQpgYGAKYGBge3IgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KcmVzdWx0cyRzaWcuYnkuY2xhc3MucGRzIDwtIHBhc3RlMChyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcywgIl8iLCByZXN1bHRzJGNsYXNzKQpyZXN1bHRzJHBzaXplIDwtIDAuMDEKcmVzdWx0cyRwc2l6ZVtyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyAmCiAgICAgICAgICAgICAgICByZXN1bHRzJGNsYXNzID09ICJDVENGX2FuZF9HNCJdIDwtIDEKCmdnc2NhdHRlcigKICByZXN1bHRzLAogIHggPSAibG9nMi5tb2NrIiwKICB5ID0gImxvZzIucGRzIiwKICBzaXplID0gMC41LAogIGFscGhhID0gcmVzdWx0cyRwc2l6ZSwKICBjb2xvciA9ICJzaWcuYnkuY2xhc3MucGRzIiwKICBwYWxldHRlID0gYyhteXBhbFs1XSwgbXlwYWxbNV0sIG15cGFsWzVdLCBteXBhbFsyXSwgbXlwYWxbMV0pCikKYGBgCmBgYHtyIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9Cmdnc2NhdHRlcigKICByZXN1bHRzWyFncmVwbCgiTkEiLCByZXN1bHRzJHNpZy5ieS5jbGFzcy5wZHMpLCBdLAogIHggPSAibG9nMi5tb2NrIiwKICB5ID0gImRlc2VxLmxmYy5wZHMiLAogIHNpemUgPSAwLjIsCiAgYWxwaGEgPSAicHNpemUiLAogIGNvbG9yID0gInNpZy5ieS5jbGFzcy5wZHMiLAogIHBhbGV0dGUgPSBjKCIjNTA1MDUwIiwgIiM1MDUwNTAiLCAicmVkMiIsICJibHVlIikKKQpgYGAKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTV9Cmdnc2NhdHRlcmhpc3QoCiAgcmVzdWx0c1shZ3JlcGwoIk5BIiwgcmVzdWx0cyRzaWcuYnkuY2xhc3MucGRzKSwgXSwKICB4ID0gImxvZzIubW9jayIsCiAgeSA9ICJsb2cyLnBkcyIsCiAgc2l6ZSA9IDAuNCwKICBhbHBoYSA9ICJwc2l6ZSIsCiAgY29sb3IgPSAic2lnLmJ5LmNsYXNzLnBkcyIsCiAgbWFyZ2luLnBhcmFtcyA9IGxpc3QoCiAgICBmaWxsID0gInNpZy5ieS5jbGFzcy5wZHMiLAogICAgY29sb3IgPSAiYmxhY2siLAogICAgc2l6ZSA9IDAuMgogICksCiAgcGFsZXR0ZSA9IGMoIiM1MDUwNTAiLCAiIzUwNTA1MCIsICJyZWQyIiwgImJsdWUiKQopCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2dzY2F0dGVyKAogIHJlc3VsdHMsCiAgeCA9ICJyYXcubGZjLnBkcyIsCiAgeSA9ICJsb2cyLkc0IiwKICBzaXplID0gMC4yLAogIGFscGhhID0gMC4xLAogIGNvbG9yID0gImRlc2VxLnNpZy5wZHMiLAogIGNvci5jb2VmID0gVCwKICBwYWxldHRlID0gYygiIzg4ODg4OCIsbXlwYWxbMl0pCikKZ2dzYXZlKGdsdWUoIntwbG90X2ZvbGRlcn1TY2F0dGVyX0c0X3ZzX0xGQ19QRFMucGRmIiksCiAgICAgICBwbG90ID0gcmFzdGVyaXplKGxhc3RfcGxvdCgpKSkKYGBgCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9Cmdnc2NhdHRlcigKICByZXN1bHRzLAogIHggPSAicmF3LmxmYy5wZGMiLAogIHkgPSAibG9nMi5HNCIsCiAgc2l6ZSA9IDAuMiwKICBhbHBoYSA9IDAuMSwKICBjb2xvciA9ICJkZXNlcS5zaWcucGRjIiwKICBjb3IuY29lZiA9IFQsCiAgcGFsZXR0ZSA9IGMoIiM4ODg4ODgiLG15cGFsWzJdKQopCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9U2NhdHRlcl9HNF92c19MRkNfUERDLnBkZiIpLAogICAgICAgcGxvdCA9IHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcmVzdWx0cyRHNC5xdWFudGlsZSA8LSBkcGx5cjo6bnRpbGUocmVzdWx0cyRHNF9OVCwgbiA9IDUpCnJlc3VsdHMkcGRzLnF1YW50aWxlIDwtIGRwbHlyOjpudGlsZShyZXN1bHRzJG1lYW4ucGRzLXJlc3VsdHMkbWVhbi5tb2NrLCBuID0gNCkKcmVzdWx0cyRwZGMucXVhbnRpbGUgPC0gZHBseXI6Om50aWxlKHJlc3VsdHMkbWVhbi5wZGMtcmVzdWx0cyRtZWFuLm1vY2ssIG4gPSA0KQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0zfQp0YiA8LSB0YWJsZShyZXN1bHRzJHBkcy5xdWFudGlsZSwgcmVzdWx0cyRjbGFzcykKdGIKZ2diYXJwbG90KGFzLmRhdGEuZnJhbWUodChhcy5tYXRyaXgodGIpKSksIlZhcjIiLCJGcmVxIixmaWxsPSJWYXIxIixwYWxldHRlID0gYyhteXBhbFsxXSwiI2FhYWFhYSIpLGxhYmVsID0gVFJVRSwgbGFiLnBvcz0iaW4iLHlsaW09YygxMTAwMCwxMzAwMCkpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9QmFycGxvdF9wZWFrQ2F0X2J5X1BEU3F1YW50aWxlLnBkZiIpLAogICAgICAgcGxvdCA9IGxhc3RfcGxvdCgpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJwZHMucXVhbnRpbGUiLAogIHkgPSAiZGVzZXEubGZjLnBkcyIsCiAgZmlsbCA9IG15cGFsWzNdLAogIGFkZCA9ICJtZWRpYW5faXFyIgopICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0xLjUsIDEuNSkpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRvdHRlZCIpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9VmlvbGluX2xmY1BEU19ieV9QRFNxdWFudGlsZS5wZGYiKSwKICAgICAgIHBsb3QgPSBsYXN0X3Bsb3QoKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQp0b3AyNS5wZHMgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHJlc3VsdHNbcmVzdWx0cyRwZHMucXVhbnRpbGU9PTQsMTozXSxuYS5ybT1UKQpib3Q3NS5wZHMgPC0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKHJlc3VsdHNbcmVzdWx0cyRwZHMucXVhbnRpbGUhPTQsMTozXSxuYS5ybT1UKQpwMSA8LSBwbG90X2J3X3Byb2ZpbGUoYndmaWxlcyA9IGdlb19iaWd3aWdzLGxvY2kgPSB0b3AyNS5wZHMsIG1vZGUgPSAiY2VudGVyIix2ZXJib3NlID0gRiwgY29sb3JzID0gbXlwYWwpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDYpKQpwMiA8LSBwbG90X2J3X3Byb2ZpbGUoYndmaWxlcyA9IGdlb19iaWd3aWdzLGxvY2kgPSBib3Q3NS5wZHMsIG1vZGUgPSAiY2VudGVyIix2ZXJib3NlID0gRiwgY29sb3JzID0gbXlwYWwpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDYpKQpnZ2FycmFuZ2UocDEscDIsIG5jb2w9MikKZ2dzYXZlKGdsdWUoIntwbG90X2ZvbGRlcn1Qcm9maWxlX0NUQ0ZfdG9wMjVfUERTcXVhbnRpbGUucGRmIiksCiAgICAgICBwbG90ID0gbGFzdF9wbG90KCkpCmBgYApgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQp0b3AyNS5wZHMuQ1RDRl9HNCA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUocmVzdWx0c1socmVzdWx0cyRwZHMucXVhbnRpbGU9PTQgJiByZXN1bHRzJGNsYXNzID09ICJDVENGX2FuZF9HNCIpLDE6M10sbmEucm09VCkKdG9wMjUucGRzLkNUQ0Zfb25seSA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUocmVzdWx0c1socmVzdWx0cyRwZHMucXVhbnRpbGU9PTQgICYgIHJlc3VsdHMkY2xhc3MgPT0gIkNUQ0Zfbm90X0c0IiksMTozXSxuYS5ybT1UKQoKcDEgPC0gcGxvdF9id19wcm9maWxlKGJ3ZmlsZXMgPSBnZW9fYmlnd2lnc1sxOjJdLGxvY2kgPSB0b3AyNS5wZHMuQ1RDRl9HNCwgbW9kZSA9ICJjZW50ZXIiLHZlcmJvc2UgPSBGLCBjb2xvcnMgPSBteXBhbFtjKDEsMildKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxMCkpCnAyIDwtIHBsb3RfYndfcHJvZmlsZShid2ZpbGVzID0gZ2VvX2JpZ3dpZ3NbMToyXSxsb2NpID0gdG9wMjUucGRzLkNUQ0Zfb25seSwgbW9kZSA9ICJjZW50ZXIiLHZlcmJvc2UgPSBGLCBjb2xvcnMgPSBteXBhbFtjKDEsMildKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxMCkpCmdnYXJyYW5nZShwMSxwMiwgbmNvbD0yKQpnZ3NhdmUoZ2x1ZSgie3Bsb3RfZm9sZGVyfVByb2ZpbGVfQ1RDRl90b3AyNV9QRFNxdWFudGlsZV9ieUc0b3ZlcmxhcC5wZGYiKSwKICAgICAgIHBsb3QgPSBsYXN0X3Bsb3QoKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQp0b3AyNS5wZHMuQ1RDRl9HNCA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUocmVzdWx0c1socmVzdWx0cyRwZHMucXVhbnRpbGU9PTQgJiByZXN1bHRzJGNsYXNzID09ICJDVENGX2FuZF9HNCIpLDE6M10sbmEucm09VCkKdG9wMjUucGRzLkNUQ0Zfb25seSA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUocmVzdWx0c1socmVzdWx0cyRwZHMucXVhbnRpbGU9PTQgICYgIHJlc3VsdHMkY2xhc3MgPT0gIkNUQ0Zfbm90X0c0IiksMTozXSxuYS5ybT1UKQoKcDEgPC0gcGxvdF9id19wcm9maWxlKGJ3ZmlsZXMgPSBnZW9fYmlnd2lnc1syXSxiZ19id2ZpbGVzID0gZ2VvX2JpZ3dpZ3NbMV0sIGxvY2kgPSB0b3AyNS5wZHMuQ1RDRl9HNCwgbW9kZSA9ICJjZW50ZXIiLHZlcmJvc2UgPSBGLCBjb2xvcnMgPSBteXBhbFsyXSxub3JtX21vZGUgPSAibG9nMmZjIixzaG93X2Vycm9yID0gVCkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC0xLDEpKQpwMiA8LSBwbG90X2J3X3Byb2ZpbGUoYndmaWxlcyA9IGdlb19iaWd3aWdzWzJdLGJnX2J3ZmlsZXMgPSBnZW9fYmlnd2lnc1sxXSwgbG9jaSA9IHRvcDI1LnBkcy5DVENGX29ubHksIG1vZGUgPSAiY2VudGVyIix2ZXJib3NlID0gRiwgY29sb3JzID0gbXlwYWxbMl0sbm9ybV9tb2RlID0gImxvZzJmYyIsc2hvd19lcnJvciA9IFQpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtMSwxKSkKZ2dhcnJhbmdlKHAxLHAyLCBuY29sPTIpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9UHJvZmlsZV9DVENGZm9sZGNoYW5nZV90b3AyNV9QRFNxdWFudGlsZV9ieUc0LnBkZiIpLAogICAgICAgcGxvdCA9IGxhc3RfcGxvdCgpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTN9CnRvcDI1LnBkcy5DVENGX0c0IDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShyZXN1bHRzWyhyZXN1bHRzJHBkcy5xdWFudGlsZT09NCAmIHJlc3VsdHMkY2xhc3MgPT0gIkNUQ0ZfYW5kX0c0IiksMTozXSxuYS5ybT1UKQp0b3AyNS5wZHMuQ1RDRl9vbmx5IDwtIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShyZXN1bHRzWyhyZXN1bHRzJHBkcy5xdWFudGlsZT09NCAgJiAgcmVzdWx0cyRjbGFzcyA9PSAiQ1RDRl9ub3RfRzQiKSwxOjNdLG5hLnJtPVQpCgpwMSA8LSBwbG90X2J3X3Byb2ZpbGUoYndmaWxlcyA9IEc0X2JpZ3dpZ3MsIGxvY2kgPSB0b3AyNS5wZHMuQ1RDRl9HNCwgbW9kZSA9ICJjZW50ZXIiLHZlcmJvc2UgPSBGLCBjb2xvcnMgPSBteXBhbFszXSxub3JtX21vZGUgPSAibG9nMmZjIikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsMTApKQpwMiA8LSBwbG90X2J3X3Byb2ZpbGUoYndmaWxlcyA9IEc0X2JpZ3dpZ3MsIGxvY2kgPSB0b3AyNS5wZHMuQ1RDRl9vbmx5LCBtb2RlID0gImNlbnRlciIsdmVyYm9zZSA9IEYsIGNvbG9ycyA9IG15cGFsWzNdLG5vcm1fbW9kZSA9ICJsb2cyZmMiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxMCkpCmdnYXJyYW5nZShwMSxwMiwgbmNvbD0yKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpvcmQudG9wMjUgPC0gb3JkZXIocm93TWVhbnMoYXMuZGF0YS5mcmFtZShid19oZWF0bWFwKGJ3ZmlsZXMgPSBnZW9fYmlnd2lnc1sxXSxsb2NpID0gdG9wMjUucGRzLCBtb2RlID0gImNlbnRlciIpKSkpCnAxIDwtIHBsb3RfYndfaGVhdG1hcChid2ZpbGVzID0gZ2VvX2JpZ3dpZ3NbMV0sbG9jaSA9IHRvcDI1LnBkcywgbW9kZSA9ICJjZW50ZXIiLHZlcmJvc2UgPSBGLCB6bWF4ID0gMTAsIG1heF9yb3dzX2FsbG93ZWQgPSA1MCwgb3JkZXJfYnkgPSBvcmQudG9wMjUpCnAyIDwtIHBsb3RfYndfaGVhdG1hcChid2ZpbGVzID0gZ2VvX2JpZ3dpZ3NbMl0sbG9jaSA9IHRvcDI1LnBkcywgbW9kZSA9ICJjZW50ZXIiLHZlcmJvc2UgPSBGLCB6bWF4ID0gMTAsIG1heF9yb3dzX2FsbG93ZWQgPSA1MCwgb3JkZXJfYnkgPSBvcmQudG9wMjUpCmdnYXJyYW5nZShwMSxwMiwgbmNvbD0yLCBjb21tb24ubGVnZW5kID0gVCkKZ2dzYXZlKGdsdWUoIntwbG90X2ZvbGRlcn1IZWF0bWFwX0NUQ0ZfdG9wMjVfUERTcXVhbnRpbGUucGRmIiksCiAgICAgICBwbG90ID0gbGFzdF9wbG90KCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9NH0Kb3JkLmJvdDc1IDwtIG9yZGVyKHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoYndfaGVhdG1hcChid2ZpbGVzID0gZ2VvX2JpZ3dpZ3NbMV0sbG9jaSA9IGJvdDc1LnBkcywgbW9kZSA9ICJjZW50ZXIiKSkpKQpwMSA8LSBwbG90X2J3X2hlYXRtYXAoYndmaWxlcyA9IGdlb19iaWd3aWdzWzFdLGxvY2kgPSBib3Q3NS5wZHMsIG1vZGUgPSAiY2VudGVyIix2ZXJib3NlID0gRiwgem1heCA9IDEwLCBtYXhfcm93c19hbGxvd2VkID0gMjAwLCBvcmRlcl9ieSA9IG9yZC5ib3Q3NSkKcDIgPC0gcGxvdF9id19oZWF0bWFwKGJ3ZmlsZXMgPSBnZW9fYmlnd2lnc1syXSxsb2NpID0gYm90NzUucGRzLCBtb2RlID0gImNlbnRlciIsdmVyYm9zZSA9IEYsIHptYXggPSAxMCwgbWF4X3Jvd3NfYWxsb3dlZCA9IDIwMCwgb3JkZXJfYnkgPSBvcmQuYm90NzUpCmdnYXJyYW5nZShwMSxwMiwgbmNvbD0yLCBjb21tb24ubGVnZW5kID0gVCkKZ2dzYXZlKGdsdWUoIntwbG90X2ZvbGRlcn1IZWF0bWFwX0NUQ0ZfYm90NzVfUERTcXVhbnRpbGUucGRmIiksCiAgICAgICBwbG90ID0gbGFzdF9wbG90KCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KRzRfQ25SIDwtIGJ3X2xvY2koYygiLi4vbWVuZGVsZXkvRmlndXJlUzIvR1NNNjYzNDMyNV9FMTRfTW9ja19HNC5idyIsIi4uL21lbmRlbGV5L0ZpZ3VyZVMyL0dTTTY2MzQzMjZfRTE0X1BEU19HNC5idyIpLGxvY2kgPSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUocmVzdWx0cyxuYS5ybT1UKSxsYWJlbHMgPSBjKCJNb2NrIiwiUERTIikpCnJlc3VsdHMkRzRfQ25SX2RlbHRhIDwtIEc0X0NuUiRQRFMtRzRfQ25SJE1vY2sKcmVzdWx0cyRHNF9DblJfbGZjIDwtIGxvZzIoRzRfQ25SJFBEUy9HNF9DblIkTW9jaykKcmVzdWx0cyRHNF9DblJfbW9jayA8LSBHNF9DblIkTW9jawpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTJ9CmdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJwZHMucXVhbnRpbGUiLAogIHkgPSAiRzRfQ25SX2RlbHRhIiwKICBmaWxsID0gbXlwYWxbMl0sCiAgYWRkID0gIm1lZGlhbl9pcXIiCikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTEwLCAxNSkpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRvdHRlZCIpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9VmlvbGluX0c0X0NuUl9kZWx0YV9ieV9QRFNxdWFudGlsZS5wZGYiKSwKICAgICAgIHBsb3QgPSBsYXN0X3Bsb3QoKSkKYGBgCmBgYHtyfQpjb21wYXJlX21lYW5zKEc0X0NuUl9kZWx0YSB+IHBkcy5xdWFudGlsZSwgcmVzdWx0cykKYGBgCmBgYHtyfQpyZXN1bHRzJHBkcy5xdWFydGlsZS50b3AyNSA8LSByZXN1bHRzJHBkcy5xdWFudGlsZSA9PSA0Cm1lYW4obmEub21pdChyZXN1bHRzJEc0X0NuUl9kZWx0YSkpCm1lYW4ocmVzdWx0cyRHNF9DblJfZGVsdGFbcmVzdWx0cyRwZHMucXVhcnRpbGUudG9wMjVdKQptZWFuKHJlc3VsdHMkRzRfQ25SX2RlbHRhWyFyZXN1bHRzJHBkcy5xdWFydGlsZS50b3AyNV0pCmNvbXBhcmVfbWVhbnMoRzRfQ25SX2RlbHRhIH4gcGRzLnF1YXJ0aWxlLnRvcDI1LCByZXN1bHRzKQpgYGAKCgpgYGB7cn0KZXhwb3J0LmJlZCh0b3AyNS5wZHMsIi4uL3BlYWtzL0NUQ0ZfcGVha3NfdG9wMjVfcGRzX3VwLmJlZCIpCmV4cG9ydC5iZWQoYm90NzUucGRzLCIuLi9wZWFrcy9DVENGX3BlYWtzX2JvdDc1X3Bkc191cC5iZWQiKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJHNC5xdWFudGlsZSIsCiAgeSA9ICJkZXNlcS5sZmMucGRzIiwKICBmaWxsID0gbXlwYWxbMV0sCiAgYWRkID0gIm1lZGlhbl9pcXIiCikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTIsIDIpKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkb3R0ZWQiKQpnZ3NhdmUoZ2x1ZSgie3Bsb3RfZm9sZGVyfVZpb2xpbl9DVENGX2xmY19ieV9HNHF1YW50aWxlLnBkZiIpLAogICAgICAgcGxvdCA9IGxhc3RfcGxvdCgpKQpgYGAKCgoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2d2aW9saW4oCiAgcmVzdWx0cywKICB4ID0gIkc0LnF1YW50aWxlIiwKICB5ID0gImxvZzIuRzQiLAogIGZpbGwgPSBteXBhbDJbNV0sCiAgYWRkID0gIm1lZGlhbl9pcXIiCikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKQpnZ3NhdmUoZ2x1ZSgie3Bsb3RfZm9sZGVyfVZpb2xpbl9HNF9ieV9HNHF1YW50aWxlLnBkZiIpLCBwbG90ID0gbGFzdF9wbG90KCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcGVha19jYXRzIDwtIGJlZHNjb3V0OjppbXBvcnRfbmFtZWRfYmVkX2ludG9fbGlzdChwZWFrc19iZWQpCnBsb3RfYndfcHJvZmlsZSgKICBHNF9iaWd3aWdzLAogIHBlYWtfY2F0cywKICBsYWJlbHMgPSBjKAogICAgcGVha19jYXRzW1sxXV1bMSwgXSRuYW1lLAogICAgcGVha19jYXRzW1syXV1bMSwgXSRuYW1lLAogICAgcGVha19jYXRzW1szXV1bMSwgXSRuYW1lLAogICAgcGVha19jYXRzW1s0XV1bMSwgXSRuYW1lCiAgKSwKICBtb2RlID0gImNlbnRlciIsCiAgc2hvd19lcnJvciA9IFQsCiAgdmVyYm9zZSA9IEYsCiAgcmVtb3ZlX3RvcCA9IDAuMDAxLAogIGNvbG9ycyA9IG15cGFsCikKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpwbG90X2J3X3Byb2ZpbGUoCiAgY29tYmluZWRfYmlnd2lnc1sxXSwKICBwZWFrX2NhdHMsCiAgbGFiZWxzID0gYygKICAgIHBlYWtfY2F0c1tbMV1dWzEsIF0kbmFtZSwKICAgIHBlYWtfY2F0c1tbMl1dWzEsIF0kbmFtZSwKICAgIHBlYWtfY2F0c1tbM11dWzEsIF0kbmFtZSwKICAgIHBlYWtfY2F0c1tbNF1dWzEsIF0kbmFtZQogICksCiAgbW9kZSA9ICJjZW50ZXIiLAogIHNob3dfZXJyb3IgPSBULAogIHZlcmJvc2UgPSBGLAogIHJlbW92ZV90b3AgPSAwLjAwMSwKICBjb2xvcnMgPSBteXBhbAopCmBgYAoKCgoKYGBge3IgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTN9CnAxIDwtIHBsb3RfYndfcHJvZmlsZSgKICBjKG1vY2tzX2JpZ3dpZ3MsIHBkc19iaWd3aWdzKSwKICBwZWFrX2NhdHNbWzFdXSwKICBsYWJlbHMgPSBjKCJtb2NrMSIsICJtb2NrMiIsICJ0cnQxIiwgInJ0cjIiKSwKICBtb2RlID0gImNlbnRlciIsCiAgc2hvd19lcnJvciA9IFQsCiAgdmVyYm9zZSA9IEYsCiAgcmVtb3ZlX3RvcCA9IDAuMDAxLAogIGNvbG9ycyA9IG15cGFsMltjKDksIDEwLCA1LCA2KV0sCiAgdXBzdHJlYW0gPSAxNTAwLAogIGRvd25zdHJlYW0gPSAxNTAwCikKcDIgPC0gcGxvdF9id19wcm9maWxlKAogIGMobW9ja3NfYmlnd2lncywgcGRzX2JpZ3dpZ3MpLAogIHBlYWtfY2F0c1tbMl1dLAogIGxhYmVscyA9IGMoIm1vY2sxIiwgIm1vY2syIiwgInRydDEiLCAicnRyMiIpLAogIG1vZGUgPSAiY2VudGVyIiwKICBzaG93X2Vycm9yID0gVCwKICB2ZXJib3NlID0gRiwKICByZW1vdmVfdG9wID0gMC4wMDEsCiAgY29sb3JzID0gbXlwYWwyW2MoOSwgMTAsIDUsIDYpXSwKICB1cHN0cmVhbSA9IDE1MDAsCiAgZG93bnN0cmVhbSA9IDE1MDAKKQpwMyA8LSBwbG90X2J3X3Byb2ZpbGUoCiAgYyhtb2Nrc19iaWd3aWdzLCBwZHNfYmlnd2lncyksCiAgcGVha19jYXRzW1szXV0sCiAgbGFiZWxzID0gYygibW9jazEiLCAibW9jazIiLCAidHJ0MSIsICJydHIyIiksCiAgbW9kZSA9ICJjZW50ZXIiLAogIHNob3dfZXJyb3IgPSBULAogIHZlcmJvc2UgPSBGLAogIHJlbW92ZV90b3AgPSAwLjAwMSwKICBjb2xvcnMgPSBteXBhbDJbYyg5LCAxMCwgNSwgNildLAogIHVwc3RyZWFtID0gMTUwMCwKICBkb3duc3RyZWFtID0gMTUwMAopCnA0IDwtIHBsb3RfYndfcHJvZmlsZSgKICBjKG1vY2tzX2JpZ3dpZ3MsIHBkc19iaWd3aWdzKSwKICBwZWFrX2NhdHNbWzRdXSwKICBsYWJlbHMgPSBjKCJtb2NrMSIsICJtb2NrMiIsICJ0cnQxIiwgInJ0cjIiKSwKICBtb2RlID0gImNlbnRlciIsCiAgc2hvd19lcnJvciA9IFQsCiAgdmVyYm9zZSA9IEYsCiAgcmVtb3ZlX3RvcCA9IDAuMDAxLAogIGNvbG9ycyA9IG15cGFsMltjKDksIDEwLCA1LCA2KV0sCiAgdXBzdHJlYW0gPSAxNTAwLAogIGRvd25zdHJlYW0gPSAxNTAwCikKCmdnYXJyYW5nZShwMSwgcDIsIHAzLCBwNCwgbmNvbCA9IDQsIG5yb3cgPSAxKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0zfQpwMSA8LSBwbG90X2J3X3Byb2ZpbGUoCiAgYyhtb2Nrc19iaWd3aWdzLCBwZHNfYmlnd2lncyksCiAgcGVha19jYXRzW1sxXV0sCiAgbGFiZWxzID0gYygibW9jazEiLCAibW9jazIiLCAidHJ0MSIsICJydHIyIiksCiAgbW9kZSA9ICJjZW50ZXIiLAogIHNob3dfZXJyb3IgPSBULAogIHZlcmJvc2UgPSBGLAogIHJlbW92ZV90b3AgPSAwLjAwMSwKICBjb2xvcnMgPSBteXBhbDJbYyg5LCAxMCwgMywgNCldLAogIHVwc3RyZWFtID0gMTUwMCwKICBkb3duc3RyZWFtID0gMTUwMAopCnAyIDwtIHBsb3RfYndfcHJvZmlsZSgKICBjKG1vY2tzX2JpZ3dpZ3MsIHBkc19iaWd3aWdzKSwKICBwZWFrX2NhdHNbWzJdXSwKICBsYWJlbHMgPSBjKCJtb2NrMSIsICJtb2NrMiIsICJ0cnQxIiwgInJ0cjIiKSwKICBtb2RlID0gImNlbnRlciIsCiAgc2hvd19lcnJvciA9IFQsCiAgdmVyYm9zZSA9IEYsCiAgcmVtb3ZlX3RvcCA9IDAuMDAxLAogIGNvbG9ycyA9IG15cGFsMltjKDksIDEwLCAzLCA0KV0sCiAgdXBzdHJlYW0gPSAxNTAwLAogIGRvd25zdHJlYW0gPSAxNTAwCikKcDMgPC0gcGxvdF9id19wcm9maWxlKAogIGMobW9ja3NfYmlnd2lncywgcGRzX2JpZ3dpZ3MpLAogIHBlYWtfY2F0c1tbM11dLAogIGxhYmVscyA9IGMoIm1vY2sxIiwgIm1vY2syIiwgInRydDEiLCAicnRyMiIpLAogIG1vZGUgPSAiY2VudGVyIiwKICBzaG93X2Vycm9yID0gVCwKICB2ZXJib3NlID0gRiwKICByZW1vdmVfdG9wID0gMC4wMDEsCiAgY29sb3JzID0gbXlwYWwyW2MoOSwgMTAsIDMsIDQpXSwKICB1cHN0cmVhbSA9IDE1MDAsCiAgZG93bnN0cmVhbSA9IDE1MDAKKQpwNCA8LSBwbG90X2J3X3Byb2ZpbGUoCiAgYyhtb2Nrc19iaWd3aWdzLCBwZHNfYmlnd2lncyksCiAgcGVha19jYXRzW1s0XV0sCiAgbGFiZWxzID0gYygibW9jazEiLCAibW9jazIiLCAidHJ0MSIsICJydHIyIiksCiAgbW9kZSA9ICJjZW50ZXIiLAogIHNob3dfZXJyb3IgPSBULAogIHZlcmJvc2UgPSBGLAogIHJlbW92ZV90b3AgPSAwLjAwMSwKICBjb2xvcnMgPSBteXBhbDJbYyg5LCAxMCwgMywgNCldLAogIHVwc3RyZWFtID0gMTUwMCwKICBkb3duc3RyZWFtID0gMTUwMAopCgpnZ2FycmFuZ2UocDEsIHAyLCBwMywgcDQsIG5jb2wgPSA0LCBucm93ID0gMSkKYGBgCiMjIyBjZW4gd2UgbGVhcm4gc29tZXRoaW5nIGZyb20gdGhlIGdlbmVzIHdpdGggdG9wLW1vc3QgaW5jcmVhc2UgaW4gQ1RDRj8KYGBge3J9CnNpZ3VwLnBkcyA8LSByZXN1bHRzW3Jlc3VsdHMkZGVzZXEuc2lndXAucGRzLCBdCnNpZ3VwLnBkYyA8LSByZXN1bHRzW3Jlc3VsdHMkZGVzZXEuc2lndXAucGRjLCBdCgojZXhwb3J0LmJlZChzaWd1cC5wZHMsInBlYWtzX3NpZ3VwX3Bkcy5iZWQiKQojZXhwb3J0LmJlZChzaWd1cC5wZHMsInBlYWtzX3NpZ3VwX3Bkcy5iZWQiKQpgYGAKCgpgYGB7cn0KZ2doaXN0b2dyYW0ocmVzdWx0cywgIndpZHRoIiwgYWRkID0gIm1lZGlhbiIsIGZpbGwgPSAiY2xhc3MiKQpgYGAKCiMjIyBEaXN0YW5jZS1iYXNlZCBhbmFseXNpcwoKYGBge3J9Ckc0X2JlZCA8LSBpbXBvcnQoJy4uL2RhdGEvRzRfQ25UL0c0X1dUX3BlYWtzLm5hcnJvd1BlYWsnKQpBVEFDX2JlZCA8LSBpbXBvcnQoJy4uL2RhdGEvQVRBQy1zZXEvQVRBQ19zZXFfbUVTQ19NYXJ0aXJlX3BlYWtzLm5hcnJvd1BlYWsnKQpwcm9fYmVkIDwtIGltcG9ydCgnLi4vZGF0YS9yZWdpb25zL3Byb21vdGVyc19nZW5lU3ltYm9sLm1tMTAuYmVkJykKCkc0X2JlZCA8LSBiZWRzY291dDo6YW5ub3RhdGVfb3ZlcmxhcHBpbmdfZmVhdHVyZXMoRzRfYmVkLCBwcm9fYmVkLCBuYW1lX2ZpZWxkID0gIm5hbWUiKQoKRzRfYmVkJG5hbWUgPC0gIkc0IgpHNF9iZWQkbmFtZVshaXMubmEoRzRfYmVkJG5lYXJieV9mZWF0dXJlcyldIDwtICJHNHBybyIKRzRfYmVkJG5hbWVbZ3JlcGwoInBybyIsIEc0X2JlZCRuYW1lKV0gPC0gIkc0cHJvIgpgYGAKCmBgYHtyfQpuZWFyZXN0X0c0XzFrYiA8LSBiZWRzY291dDo6YW5ub3RhdGVfbmVhcmJ5X2ZlYXR1cmVzKAogIGN0Y2YsCiAgRzRfYmVkLAogIGRpc3RhbmNlX2N1dG9mZiA9IDEwMDAsCiAgaWdub3JlLnN0cmFuZCA9IFQsCiAgbmFtZV9maWVsZCA9ICJuYW1lIgopCm5lYXJlc3RfRzRfMi41a2IgPC0gYmVkc2NvdXQ6OmFubm90YXRlX25lYXJieV9mZWF0dXJlcygKICBjdGNmLAogIEc0X2JlZCwKICBkaXN0YW5jZV9jdXRvZmYgPSAyNTAwLAogIGlnbm9yZS5zdHJhbmQgPSBULAogIG5hbWVfZmllbGQgPSAibmFtZSIKKQpuZWFyZXN0X0c0XzVrYiA8LSBiZWRzY291dDo6YW5ub3RhdGVfbmVhcmJ5X2ZlYXR1cmVzKAogIGN0Y2YsCiAgRzRfYmVkLAogIGRpc3RhbmNlX2N1dG9mZiA9IDUwMDAsCiAgaWdub3JlLnN0cmFuZCA9IFQsCiAgbmFtZV9maWVsZCA9ICJuYW1lIgopCm5lYXJlc3RfRzRfMTBrYiA8LSBiZWRzY291dDo6YW5ub3RhdGVfbmVhcmJ5X2ZlYXR1cmVzKAogIGN0Y2YsCiAgRzRfYmVkLAogIGRpc3RhbmNlX2N1dG9mZiA9IDEwMDAwLAogIGlnbm9yZS5zdHJhbmQgPSBULAogIG5hbWVfZmllbGQgPSAibmFtZSIKKQpuZWFyZXN0X0c0XzUwa2IgPC0gYmVkc2NvdXQ6OmFubm90YXRlX25lYXJieV9mZWF0dXJlcygKICBjdGNmLAogIEc0X2JlZCwKICBkaXN0YW5jZV9jdXRvZmYgPSA1MDAwMCwKICBpZ25vcmUuc3RyYW5kID0gVCwKICBuYW1lX2ZpZWxkID0gIm5hbWUiCikKCmN0Y2YkbmVhcmVzdF9HNCA8LSBmYWN0b3IoIj41MGtiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCI8MWtiIiwgIjwyLjVrYiIsICI8NWtiIiwgIjwxMGtiIiwgIjw1MGtiIiwgIj41MGtiIikpCmN0Y2YkbmVhcmVzdF9HNFshaXMubmEobmVhcmVzdF9HNF81MGtiJG5lYXJieV9mZWF0dXJlcyldIDwtICI8NTBrYiIKY3RjZiRuZWFyZXN0X0c0WyFpcy5uYShuZWFyZXN0X0c0XzEwa2IkbmVhcmJ5X2ZlYXR1cmVzKV0gPC0gIjwxMGtiIgpjdGNmJG5lYXJlc3RfRzRbIWlzLm5hKG5lYXJlc3RfRzRfNWtiJG5lYXJieV9mZWF0dXJlcyldIDwtICI8NWtiIgpjdGNmJG5lYXJlc3RfRzRbIWlzLm5hKG5lYXJlc3RfRzRfMi41a2IkbmVhcmJ5X2ZlYXR1cmVzKV0gPC0gIjwyLjVrYiIKY3RjZiRuZWFyZXN0X0c0WyFpcy5uYShuZWFyZXN0X0c0XzFrYiRuZWFyYnlfZmVhdHVyZXMpXSA8LSAiPDFrYiIKCmN0Y2YkbmVhcmVzdF9HNF90eXBlIDwtICJub25lIgpjdGNmJG5lYXJlc3RfRzRfdHlwZVshaXMubmEobmVhcmVzdF9HNF81MGtiJG5lYXJieV9mZWF0dXJlcyldIDwtIG5lYXJlc3RfRzRfNTBrYiRuZWFyYnlfZmVhdHVyZXNbIWlzLm5hKG5lYXJlc3RfRzRfNTBrYiRuZWFyYnlfZmVhdHVyZXMpXQpjdGNmJG5lYXJlc3RfRzRfdHlwZVshaXMubmEobmVhcmVzdF9HNF8xMGtiJG5lYXJieV9mZWF0dXJlcyldIDwtIG5lYXJlc3RfRzRfMTBrYiRuZWFyYnlfZmVhdHVyZXNbIWlzLm5hKG5lYXJlc3RfRzRfMTBrYiRuZWFyYnlfZmVhdHVyZXMpXQpjdGNmJG5lYXJlc3RfRzRfdHlwZVshaXMubmEobmVhcmVzdF9HNF81a2IkbmVhcmJ5X2ZlYXR1cmVzKV0gPC0gbmVhcmVzdF9HNF81a2IkbmVhcmJ5X2ZlYXR1cmVzWyFpcy5uYShuZWFyZXN0X0c0XzVrYiRuZWFyYnlfZmVhdHVyZXMpXQpjdGNmJG5lYXJlc3RfRzRfdHlwZVshaXMubmEobmVhcmVzdF9HNF8yLjVrYiRuZWFyYnlfZmVhdHVyZXMpXSA8LSBuZWFyZXN0X0c0XzIuNWtiJG5lYXJieV9mZWF0dXJlc1shaXMubmEobmVhcmVzdF9HNF8yLjVrYiRuZWFyYnlfZmVhdHVyZXMpXQpjdGNmJG5lYXJlc3RfRzRfdHlwZVshaXMubmEobmVhcmVzdF9HNF8xa2IkbmVhcmJ5X2ZlYXR1cmVzKV0gPC0gbmVhcmVzdF9HNF8xa2IkbmVhcmJ5X2ZlYXR1cmVzWyFpcy5uYShuZWFyZXN0X0c0XzFrYiRuZWFyYnlfZmVhdHVyZXMpXQoKY3RjZiRuZWFyZXN0X0c0X3R5cGVbZ3JlcCgicHJvIiwgY3RjZiRuZWFyZXN0X0c0X3R5cGUpXSA8LSAiRzRwcm8iCgpyZXN1bHRzJG5lYXJlc3RfRzQgPC0gY3RjZiRuZWFyZXN0X0c0CnJlc3VsdHMkbmVhcmVzdF9HNF90eXBlIDwtIGN0Y2YkbmVhcmVzdF9HNF90eXBlCnRhYmxlKHJlc3VsdHMkbmVhcmVzdF9HNCkKdGFibGUocmVzdWx0cyRuZWFyZXN0X0c0X3R5cGUpCnRhYmxlKHJlc3VsdHMkbmVhcmVzdF9HNCwgcmVzdWx0cyRuZWFyZXN0X0c0X3R5cGUpCmBgYApgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpnZ3Zpb2xpbigKICByZXN1bHRzLAogIHggPSAibmVhcmVzdF9HNCIsCiAgeSA9ICJtZWFuLm1vY2siLAogIGZpbGwgPSBteXBhbFsxXSwKICBhZGQgPSAibWVkaWFuX2lxciIKKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAxMCkpICsKICBzdGF0X2NvbXBhcmVfbWVhbnMobGFiZWwueSA9IDgsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnggPSAzLAogICAgICAgICAgICAgICAgICAgICBzaXplID0gMykgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRvdHRlZCIpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9VmlvbGluX0NUQ0Zfc2lnbmFsX2J5X0c0ZGlzdGFuY2UucGRmIiksCiAgICAgICBwbG90ID0gbGFzdF9wbG90KCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2d2aW9saW4oCiAgcmVzdWx0cywKICB4ID0gIm5lYXJlc3RfRzQiLAogIHkgPSAiZGVzZXEubGZjLnBkcyIsCiAgZmlsbCA9IG15cGFsWzFdLAogIGFkZCA9ICJtZWRpYW5faXFyIgopICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC00LCA0KSkgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSAwLjIpICsKICBnZW9tX2hsaW5lKAogICAgeWludGVyY2VwdCA9IG1lZGlhbihyZXN1bHRzJGRlc2VxLmxmYy5wZHNbcmVzdWx0cyRuZWFyZXN0X0c0ID09ICI8MWtiIl0pLAogICAgbGluZXR5cGUgPSAiZG90dGVkIiwKICAgIGxpbmV3aWR0aCA9IDAuMgogICkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhsYWJlbC55ID0gMywKICAgICAgICAgICAgICAgICAgICAgbGFiZWwueCA9IDIsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAzKQpnZ3NhdmUoZ2x1ZSgie3Bsb3RfZm9sZGVyfVZpb2xpbl9DVENGX1BEU19sZmNfYnlfRzRkaXN0YW5jZS5wZGYiKSwKICAgICAgIHBsb3QgPSBsYXN0X3Bsb3QoKSkKYGBgCmBgYHtyfQpuZWFyZXN0X0c0X3N0YXRzID0gY29tcGFyZV9tZWFucyhkZXNlcS5sZmMucGRzIH4gbmVhcmVzdF9HNCwgcmVzdWx0cykKbmVhcmVzdF9HNF9zdGF0cwp3cml0ZV90c3YobmVhcmVzdF9HNF9zdGF0cywKICAgICAgICAgIGdsdWUoIntzdGF0X291dHB1dH1wZHNfRzRkaXN0YW5jZV9wbG90cy1zdGF0aXN0aWNzLnRzdiIpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJuZWFyZXN0X0c0IiwKICB5ID0gImRlc2VxLmxmYy5wZGMiLAogIGZpbGwgPSBteXBhbFsxXSwKICBhZGQgPSAibWVkaWFuX2lxciIKKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMiwgMikpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gMC4yKSArIGdlb21faGxpbmUoCiAgeWludGVyY2VwdCA9IG1lYW4ocmVzdWx0cyRkZXNlcS5sZmMucGRjW3Jlc3VsdHMkbmVhcmVzdF9HNCA9PSAiPDFrYiJdKSwKICBsaW5ldHlwZSA9ICJkb3R0ZWQiLAogIGxpbmV3aWR0aCA9IDAuMgopCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9VmlvbGluX0NUQ0ZfUGhlbkRDM19sZmNfYnlfRzRkaXN0YW5jZS5wZGYiKSwgcGxvdCA9IGxhc3RfcGxvdCgpKQpgYGAKCmBgYHtyfQpuZWFyZXN0X0c0X3N0YXRzID0gY29tcGFyZV9tZWFucyhkZXNlcS5sZmMucGRjIH4gbmVhcmVzdF9HNCwgcmVzdWx0cykKbmVhcmVzdF9HNF9zdGF0cwp3cml0ZV90c3YobmVhcmVzdF9HNF9zdGF0cywgZ2x1ZSgie3N0YXRfb3V0cHV0fXBoZW5kY19HNGRpc3RhbmNlX3Bsb3RzLXN0YXRpc3RpY3MudHN2IikpCmBgYApgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0zfQpnZ3Zpb2xpbigKICByZXN1bHRzLAogIHggPSAibmVhcmVzdF9HNCIsCiAgeSA9ICJkZXNlcS5sZmMucGRzIiwKICBmaWxsID0gIm5lYXJlc3RfRzRfdHlwZSIsCiAgcGFsZXR0ZSA9IG15cGFsW2MoMSwgMywgNSldLAogIGFkZCA9ICJtZWRpYW5faXFyIgopICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0yLCA0KSkgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSAwLjIpICsgZ2VvbV9obGluZSgKICB5aW50ZXJjZXB0ID0gbWVhbihyZXN1bHRzJGRlc2VxLmxmYy5wZHNbcmVzdWx0cyRuZWFyZXN0X0c0ID09ICI8MWtiIl0pLAogIGxpbmV0eXBlID0gImRvdHRlZCIsCiAgbGluZXdpZHRoID0gMC4yCikgKwogIHN0YXRfY29tcGFyZV9tZWFucyhhZXMoZ3JvdXAgPSBuZWFyZXN0X0c0X3R5cGUpKQpnZ3NhdmUoZ2x1ZSgie3Bsb3RfZm9sZGVyfVZpb2xpbl9DVENGX1BEU19sZmNfYnlfRzRkaXN0YW5jZV9wcm8ucGRmIiksCiAgICAgICBwbG90ID0gbGFzdF9wbG90KCkpCmBgYApgYGB7cn0KY29tcGFyZV9tZWFucyhkZXNlcS5sZmMucGRzIH4gbmVhcmVzdF9HNCwgcmVzdWx0c1tyZXN1bHRzJG5lYXJlc3RfRzRfdHlwZSA9PQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkc0IiwgXSkKY29tcGFyZV9tZWFucyhkZXNlcS5sZmMucGRzIH4gbmVhcmVzdF9HNCwgcmVzdWx0c1tyZXN1bHRzJG5lYXJlc3RfRzRfdHlwZSA9PQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkc0IiwgXSkgJT4lCiAgd3JpdGVfdHN2KC4sCiAgICAgICAgICAgIGdsdWUoCiAgICAgICAgICAgICAgIntzdGF0X291dHB1dH1wZHNfRzRkaXN0YW5jZV9wbG90cy1uZWFyZXN0X0c0LXN0YXRpc3RpY3MudHN2IgogICAgICAgICAgICApKQpgYGAKYGBge3J9CmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkcyB+IG5lYXJlc3RfRzQsIHJlc3VsdHNbcmVzdWx0cyRuZWFyZXN0X0c0X3R5cGUgPT0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHNHBybyIsIF0pCmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkcyB+IG5lYXJlc3RfRzQsIHJlc3VsdHNbcmVzdWx0cyRuZWFyZXN0X0c0X3R5cGUgPT0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHNHBybyIsIF0pICU+JQogIHdyaXRlX3RzdiguLAogICAgICAgICAgICBnbHVlKAogICAgICAgICAgICAgICJ7c3RhdF9vdXRwdXR9cGRzX0c0ZGlzdGFuY2VfcGxvdHMtbmVhcmVzdF9HNHByby1zdGF0aXN0aWNzLnRzdiIKICAgICAgICAgICAgKSkKYGBgCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTN9CmdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJuZWFyZXN0X0c0IiwKICB5ID0gImRlc2VxLmxmYy5wZGMiLAogIGZpbGwgPSAibmVhcmVzdF9HNF90eXBlIiwKICBwYWxldHRlID0gbXlwYWxbYygxLCAzLCA1KV0sCiAgYWRkID0gIm1lZGlhbl9pcXIiCikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTIsIDIpKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IDAuMikgKyBnZW9tX2hsaW5lKAogIHlpbnRlcmNlcHQgPSBtZWFuKHJlc3VsdHMkZGVzZXEubGZjLnBkY1tyZXN1bHRzJG5lYXJlc3RfRzQgPT0gIjwxa2IiXSksCiAgbGluZXR5cGUgPSAiZG90dGVkIiwKICBsaW5ld2lkdGggPSAwLjIKKQpnZ3NhdmUoZ2x1ZSgKICAie3Bsb3RfZm9sZGVyfVZpb2xpbl9DVENGX1BoZW5EQzNfbGZjX2J5X0c0ZGlzdGFuY2VfcHJvLnBkZiIKKSwKcGxvdCA9IGxhc3RfcGxvdCgpKQpgYGAKCmBgYHtyfQpjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZGMgfiBuZWFyZXN0X0c0LCByZXN1bHRzW3Jlc3VsdHMkbmVhcmVzdF9HNF90eXBlID09CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRzQiLCBdKQpjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZGMgfiBuZWFyZXN0X0c0LCByZXN1bHRzW3Jlc3VsdHMkbmVhcmVzdF9HNF90eXBlID09CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRzQiLCBdKSAlPiUKICB3cml0ZV90c3YoLiwKICAgICAgICAgICAgZ2x1ZSgKICAgICAgICAgICAgICAie3N0YXRfb3V0cHV0fXBoZW5kY19HNGRpc3RhbmNlX3Bsb3RzLW5lYXJlc3RfRzQtc3RhdGlzdGljcy50c3YiCiAgICAgICAgICAgICkpCmBgYAoKYGBge3J9CmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkYyB+IG5lYXJlc3RfRzQsIHJlc3VsdHNbcmVzdWx0cyRuZWFyZXN0X0c0X3R5cGUgPT0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHNHBybyIsIF0pCmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkYyB+IG5lYXJlc3RfRzQsIHJlc3VsdHNbcmVzdWx0cyRuZWFyZXN0X0c0X3R5cGUgPT0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHNHBybyIsIF0pICU+JQogIHdyaXRlX3RzdiguLAogICAgICAgICAgICBnbHVlKAogICAgICAgICAgICAgICJ7c3RhdF9vdXRwdXR9cGhlbmRjX0c0ZGlzdGFuY2VfcGxvdHMtbmVhcmVzdF9HNHByby1zdGF0aXN0aWNzLnRzdiIKICAgICAgICAgICAgKSkKYGBgCiMjIyBEaXN0YW5jZS1iYXNlZCBhbmFseXNpcywgdGhpcyB0aW1lIHdpdGggcHJlZGljdGVkIEc0IG1vdGlmcywgbm90IGV4cGVyaW1lbnRhbCBwZWFrcwoKYGBge3J9CiNyZXN1bHRzIDwtIHJlYWQudGFibGUoZ2x1ZSgie3Jlc3VsdF9mb2xkZXJ9Zm9sZGNoYW5nZV9yZXN1bHRzLnR4dCIpKQpyZXN1bHRzJGNsYXNzIDwtIGZhY3RvcihyZXN1bHRzJGNsYXNzLCBsZXZlbHMgPSBjKCJDVENGX2FuZF9HNCIsICJDVENGX25vdF9HNCIpKQpHNF9iZWQgPC0gaW1wb3J0KCcuLi9kYXRhL0c0X0NuVC9HNF9XVF9wZWFrcy5uYXJyb3dQZWFrJykKRzRfYmVkJG5hbWUgPC0gInBlYWsiCkc0cHJlZF9iZWQgPC0gaW1wb3J0KCcuLi9kYXRhL3ByZWRHNC9tbTEwX2Nhbm9uaWNhbF9HNF9QUVMtcmVnZXguYmVkJykKQVRBQ19iZWQgPC0gaW1wb3J0KCcuLi9kYXRhL0FUQUMtc2VxL0FUQUNfc2VxX21FU0NfTWFydGlyZV9wZWFrcy5uYXJyb3dQZWFrJykKcHJvX2JlZCA8LSBpbXBvcnQoJy4uL2RhdGEvcmVnaW9ucy9wcm9tb3RlcnNfZ2VuZVN5bWJvbC5tbTEwLmJlZCcpCgpHNHByZWRfYmVkIDwtIGJlZHNjb3V0Ojphbm5vdGF0ZV9vdmVybGFwcGluZ19mZWF0dXJlcyhHNHByZWRfYmVkLCBHNF9iZWQsIG5hbWVfZmllbGQgPSAibmFtZSIpCgpHNHByZWRfYmVkJG5hbWUgPC0gIkc0cHJlZCIKRzRwcmVkX2JlZCRuYW1lW2dyZXBsKCJwZWFrIiwgRzRwcmVkX2JlZCRuZWFyYnlfZmVhdHVyZXMpXSA8LSAiRzRleHAiCgp0YWJsZShHNHByZWRfYmVkJG5hbWUpCmBgYAoKYGBge3J9Cm5lYXJlc3RfRzRfMGtiIDwtIGJlZHNjb3V0Ojphbm5vdGF0ZV9uZWFyYnlfZmVhdHVyZXMoCiAgY3RjZiwKICBHNHByZWRfYmVkLAogIGRpc3RhbmNlX2N1dG9mZiA9IDAsCiAgaWdub3JlLnN0cmFuZCA9IFQsCiAgbmFtZV9maWVsZCA9ICJuYW1lIgopCm5lYXJlc3RfRzRfMWtiIDwtIGJlZHNjb3V0Ojphbm5vdGF0ZV9uZWFyYnlfZmVhdHVyZXMoCiAgY3RjZiwKICBHNHByZWRfYmVkLAogIGRpc3RhbmNlX2N1dG9mZiA9IDEwMDAsCiAgaWdub3JlLnN0cmFuZCA9IFQsCiAgbmFtZV9maWVsZCA9ICJuYW1lIgopCm5lYXJlc3RfRzRfMi41a2IgPC0gYmVkc2NvdXQ6OmFubm90YXRlX25lYXJieV9mZWF0dXJlcygKICBjdGNmLAogIEc0cHJlZF9iZWQsCiAgZGlzdGFuY2VfY3V0b2ZmID0gMjUwMCwKICBpZ25vcmUuc3RyYW5kID0gVCwKICBuYW1lX2ZpZWxkID0gIm5hbWUiCikKbmVhcmVzdF9HNF81a2IgPC0gYmVkc2NvdXQ6OmFubm90YXRlX25lYXJieV9mZWF0dXJlcygKICBjdGNmLAogIEc0cHJlZF9iZWQsCiAgZGlzdGFuY2VfY3V0b2ZmID0gNTAwMCwKICBpZ25vcmUuc3RyYW5kID0gVCwKICBuYW1lX2ZpZWxkID0gIm5hbWUiCikKbmVhcmVzdF9HNF8xMGtiIDwtIGJlZHNjb3V0Ojphbm5vdGF0ZV9uZWFyYnlfZmVhdHVyZXMoCiAgY3RjZiwKICBHNHByZWRfYmVkLAogIGRpc3RhbmNlX2N1dG9mZiA9IDEwMDAwLAogIGlnbm9yZS5zdHJhbmQgPSBULAogIG5hbWVfZmllbGQgPSAibmFtZSIKKQoKCmN0Y2YkbmVhcmVzdF9HNCA8LSBmYWN0b3IoIj4xMGtiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCIwa2IiLCAiPDFrYiIsICI8Mi41a2IiLCAiPDVrYiIsICI8MTBrYiIsICI+MTBrYiIpKQpjdGNmJG5lYXJlc3RfRzRbIWlzLm5hKG5lYXJlc3RfRzRfMTBrYiRuZWFyYnlfZmVhdHVyZXMpXSA8LSAiPDEwa2IiCmN0Y2YkbmVhcmVzdF9HNFshaXMubmEobmVhcmVzdF9HNF81a2IkbmVhcmJ5X2ZlYXR1cmVzKV0gPC0gIjw1a2IiCmN0Y2YkbmVhcmVzdF9HNFshaXMubmEobmVhcmVzdF9HNF8yLjVrYiRuZWFyYnlfZmVhdHVyZXMpXSA8LSAiPDIuNWtiIgpjdGNmJG5lYXJlc3RfRzRbIWlzLm5hKG5lYXJlc3RfRzRfMWtiJG5lYXJieV9mZWF0dXJlcyldIDwtICI8MWtiIgpjdGNmJG5lYXJlc3RfRzRbIWlzLm5hKG5lYXJlc3RfRzRfMGtiJG5lYXJieV9mZWF0dXJlcyldIDwtICIwa2IiCgpyZXN1bHRzJG5lYXJlc3RfRzQgPC0gY3RjZiRuZWFyZXN0X0c0CnRhYmxlKHJlc3VsdHMkbmVhcmVzdF9HNCkKdGFibGUocmVzdWx0cyRuZWFyZXN0X0c0LCByZXN1bHRzJHBybykKYGBgCgoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9Mn0KbWRmIDwtIHJlc2hhcGUyOjptZWx0KHRhYmxlKHJlc3VsdHMkbmVhcmVzdF9HNCwgcmVzdWx0cyRwcm8pKQpnZ3Bsb3QobWRmLCBhZXMoVmFyMSwgVmFyMiwgZmlsbCA9IHZhbHVlKSkgKwogIGdlb21fdGlsZShzaG93LmxlZ2VuZCA9IEYpICsgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHZhbHVlKSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJvcmFuZ2UiKSArIHRoZW1lX21pbmltYWwoKQpnZ3NhdmUoZ2x1ZSgie3Bsb3RfZm9sZGVyfUhlYXRtYXBfQ1RDRl9zaXRlc19ieV9wcmVkRzRkaXN0YW5jZS5wZGYiKSwKICAgICAgIHBsb3QgPSBsYXN0X3Bsb3QoKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpnZ3Zpb2xpbigKICByZXN1bHRzLAogIHggPSAibmVhcmVzdF9HNCIsCiAgeSA9ICJtZWFuLm1vY2siLAogIGZpbGwgPSBteXBhbFsxXSwKICBhZGQgPSAibWVkaWFuX2lxciIKKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAxMCkpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRvdHRlZCIpICsKICBzdGF0X2NvbXBhcmVfbWVhbnMoCiAgICBhZXMoZ3JvdXAgPSBuZWFyZXN0X0c0KSwKICAgIGxhYmVsLnkgPSA4LAogICAgbGFiZWwueCA9IDIsCiAgICBzaXplID0gMwogICkKZ2dzYXZlKGdsdWUoCiAgIntwbG90X2ZvbGRlcn1WaW9saW5fQ1RDRl9zaWduYWxfYnlfcHJlZEc0ZGlzdGFuY2UucGRmIiksCiAgcGxvdCA9IGxhc3RfcGxvdCgpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJuZWFyZXN0X0c0IiwKICB5ID0gImRlc2VxLmxmYy5wZHMiLAogIGZpbGwgPSBteXBhbFsxXSwKICBhZGQgPSAibWVkaWFuX2lxciIKKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMC41LCAxLjUpKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IDAuMikgKyBnZW9tX2hsaW5lKAogIHlpbnRlcmNlcHQgPSBtZWRpYW4ocmVzdWx0cyRkZXNlcS5sZmMucGRzW3Jlc3VsdHMkbmVhcmVzdF9HNCA9PSAiMGtiIl0pLAogIGxpbmV0eXBlID0gImRvdHRlZCIsCiAgbGluZXdpZHRoID0gMC4yCikgKwogIHN0YXRfY29tcGFyZV9tZWFucyhsYWJlbC55ID0gMS4zLAogICAgICAgICAgICAgICAgICAgICBsYWJlbC54ID0gMywKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIpCmdnc2F2ZShnbHVlKCJ7cGxvdF9mb2xkZXJ9VmlvbGluX0NUQ0ZfUERTX2xmY19ieV9wcmVkRzRkaXN0YW5jZS5wZGYiKSwKICAgICAgIHBsb3QgPSBsYXN0X3Bsb3QoKSkKYGBgCmBgYHtyfQpjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZHMgfiBuZWFyZXN0X0c0LCByZXN1bHRzKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJuZWFyZXN0X0c0IiwKICB5ID0gImRlc2VxLmxmYy5wZGMiLAogIGZpbGwgPSBteXBhbFsxXSwKICBhZGQgPSAibWVkaWFuX2lxciIKKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtMC41LCAxLjUpKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IDAuMikgKyBnZW9tX2hsaW5lKAogIHlpbnRlcmNlcHQgPSBtZWFuKHJlc3VsdHMkZGVzZXEubGZjLnBkY1tyZXN1bHRzJG5lYXJlc3RfRzQgPT0gIjBrYiJdKSwKICBsaW5ldHlwZSA9ICJkb3R0ZWQiLAogIGxpbmV3aWR0aCA9IDAuMgopICsKICBzdGF0X2NvbXBhcmVfbWVhbnMobGFiZWwueSA9IDEuMywKICAgICAgICAgICAgICAgICAgICAgbGFiZWwueCA9IDMsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAyKQpnZ3NhdmUoZ2x1ZSgKICAie3Bsb3RfZm9sZGVyfVZpb2xpbl9DVENGX1BoZW5EQzNfbGZjX2J5X3ByZWRHNGRpc3RhbmNlLnBkZiIKKSwKcGxvdCA9IGxhc3RfcGxvdCgpKQpgYGAKCmBgYHtyfQpjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZGMgfiBuZWFyZXN0X0c0LCByZXN1bHRzKQoKYGBgCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTN9CmdndmlvbGluKAogIHJlc3VsdHMsCiAgeCA9ICJuZWFyZXN0X0c0IiwKICB5ID0gImRlc2VxLmxmYy5wZHMiLAogIGZpbGwgPSAicHJvIiwKICBwYWxldHRlID0gbXlwYWxbYygxLCAzLCA1KV0sCiAgYWRkID0gIm1lZGlhbl9pcXIiCikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTAuNSwgMS41KSkgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSAwLjIpICsgZ2VvbV9obGluZSgKICB5aW50ZXJjZXB0ID0gbWVhbihyZXN1bHRzJGRlc2VxLmxmYy5wZHNbcmVzdWx0cyRuZWFyZXN0X0c0ID09ICIwa2IiXSksCiAgbGluZXR5cGUgPSAiZG90dGVkIiwKICBsaW5ld2lkdGggPSAwLjIKKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKGFlcyhncm91cCA9IHBybyksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnkgPSAxLjMsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnggPSAzLAogICAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KQpnZ3NhdmUoZ2x1ZSgie3Bsb3RfZm9sZGVyfVZpb2xpbl9DVENGX1BEU19sZmNfYnlfcHJlZEc0ZGlzdGFuY2VfcHJvLnBkZiIpLCBwbG90ID0gbGFzdF9wbG90KCkpCmBgYApgYGB7CnIKfQpjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZHMgfiBuZWFyZXN0X0c0LCByZXN1bHRzW3Jlc3VsdHMkcHJvID09ICJub1BybyIsIF0pCmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkcyB+IG5lYXJlc3RfRzQsIHJlc3VsdHNbcmVzdWx0cyRwcm8gPT0gIm5vUHJvIiwgXSkgJT4lCndyaXRlX3RzdiguLCAicGRzX0c0ZGlzdGFuY2VfcGxvdHMtbm9Qcm8tc3RhdGlzdGljcy50c3YiKQogIApgYGAKYGBge3J9CmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkcyB+IG5lYXJlc3RfRzQsIHJlc3VsdHNbcmVzdWx0cyRwcm8gPT0gIlBybyIsIF0pICU+JQogIHdyaXRlX3RzdiguLAogICAgICAgICAgICBnbHVlKCJ7c3RhdF9vdXRwdXR9cGRzX0c0ZGlzdGFuY2VfcGxvdHMtUHJvLXN0YXRpc3RpY3MudHN2IikpCgpjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZHMgfiBwcm8sIGdyb3VwLmJ5ID0gIm5lYXJlc3RfRzQiLCByZXN1bHRzKSAlPiUKICB3cml0ZV90c3YoLiwKICAgICAgICAgICAgZ2x1ZSgKICAgICAgICAgICAgICAie3N0YXRfb3V0cHV0fXBkc19HNGRpc3RhbmNlX3Bsb3RzLWJldHdlZW5fcHJvbV90eXBlc19zdGF0cy50c3YiCiAgICAgICAgICAgICkpCgpjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZHMgfiBuZWFyZXN0X0c0LCBncm91cC5ieSA9ICJwcm8iLCByZXN1bHRzKSAlPiUKICB3cml0ZV90c3YoLiwKICAgICAgICAgICAgZ2x1ZSgKICAgICAgICAgICAgICAie3N0YXRfb3V0cHV0fXBkc19HNGRpc3RhbmNlX3Bsb3RzLXdpdGhpbl9wcm9tX3R5cGVzX3N0YXRzLnRzdiIKICAgICAgICAgICAgKSkKCmBgYApgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0zfQpnZ3Zpb2xpbigKICByZXN1bHRzLAogIHggPSAibmVhcmVzdF9HNCIsCiAgeSA9ICJkZXNlcS5sZmMucGRjIiwKICBmaWxsID0gInBybyIsCiAgcGFsZXR0ZSA9IG15cGFsW2MoMSwgMywgNSldLAogIGFkZCA9ICJtZWRpYW5faXFyIgopICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0wLjUsIDEuNSkpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gMC4yKSArIGdlb21faGxpbmUoCiAgeWludGVyY2VwdCA9IG1lYW4ocmVzdWx0cyRkZXNlcS5sZmMucGRjW3Jlc3VsdHMkbmVhcmVzdF9HNCA9PSAiMGtiIl0pLAogIGxpbmV0eXBlID0gImRvdHRlZCIsCiAgbGluZXdpZHRoID0gMC4yCikgKwogIHN0YXRfY29tcGFyZV9tZWFucyhhZXMoZ3JvdXAgPSBwcm8pLAogICAgICAgICAgICAgICAgICAgICBsYWJlbC55ID0gMS4zLAogICAgICAgICAgICAgICAgICAgICBsYWJlbC54ID0gMywKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkKZ2dzYXZlKGdsdWUoCiAgIntwbG90X2ZvbGRlcn1WaW9saW5fQ1RDRl9QaGVuREMzX2xmY19ieV9wcmVkRzRkaXN0YW5jZV9wcm8ucGRmIgopLApwbG90ID0gbGFzdF9wbG90KCkpCmBgYAoKYGBge3J9CmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkYyB+IG5lYXJlc3RfRzQsIHJlc3VsdHNbcmVzdWx0cyRwcm8gPT0gIm5vUHJvIiwgXSkgJT4lCiAgd3JpdGVfdHN2KC4sCiAgICAgICAgICAgIGdsdWUoCiAgICAgICAgICAgICAgIntzdGF0X291dHB1dH1waGVuZGNfRzRkaXN0YW5jZV9wbG90cy1ub1Byby1zdGF0aXN0aWNzLnRzdiIKICAgICAgICAgICAgKSkKCmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkYyB+IHBybywgZ3JvdXAuYnkgPSAibmVhcmVzdF9HNCIsIHJlc3VsdHMpICU+JQogIHdyaXRlX3RzdiguLAogICAgICAgICAgICBnbHVlKAogICAgICAgICAgICAgICJ7c3RhdF9vdXRwdXR9cGhlbmRjX0c0ZGlzdGFuY2VfcGxvdHMtYmV0d2Vlbl9wcm9tX3R5cGVzX3N0YXRzLnRzdiIKICAgICAgICAgICAgKSkKCmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkYyB+IG5lYXJlc3RfRzQsIGdyb3VwLmJ5ID0gInBybyIsIHJlc3VsdHMpICU+JQogIHdyaXRlX3RzdiguLAogICAgICAgICAgICBnbHVlKAogICAgICAgICAgICAgICJ7c3RhdF9vdXRwdXR9cGhlbmRjX0c0ZGlzdGFuY2VfcGxvdHMtd2l0aGluX3Byb21fdHlwZXNfc3RhdHMudHN2IgogICAgICAgICAgICApKQoKCmBgYAo=